funwithlinux blog

How to Fix 'stdin: is not a tty' SSH Error When Executing Remote Commands Through Another Machine

If you’ve ever tried to run a remote command over SSH—especially through intermediate machines (e.g., jump hosts)—you may have encountered the frustrating error: stdin: is not a tty. This error typically arises when the remote command expects an interactive terminal (TTY) but SSH fails to allocate one, or when a non-interactive command mistakenly requests terminal input.

In this blog, we’ll demystify this error, explore its root causes, and provide step-by-step solutions to resolve it. Whether you’re executing simple commands, chaining SSH hops, or running scripts that use sudo, we’ll cover scenarios you’re likely to encounter and how to fix them.

2026-01

Table of Contents#

  1. What is the 'stdin: is not a tty' Error?
  2. Common Scenarios Where the Error Occurs
  3. Root Causes of the Error
  4. Step-by-Step Solutions
  5. Troubleshooting Tips
  6. Conclusion
  7. References

What is the 'stdin: is not a tty' Error?#

Understanding TTYs and stdin#

To grasp this error, we first need to understand two key concepts:

  • TTY (Teletypewriter): A TTY is a device file that represents an interactive terminal. It allows bidirectional communication between a user and a program (e.g., input from a keyboard, output to a screen). On modern systems, TTYs are often virtual (e.g., /dev/pts/0 for terminal emulators).
  • stdin (Standard Input): stdin is a data stream that provides input to a program. By default, it’s connected to the terminal (TTY) in interactive sessions, but in non-interactive sessions (like SSH commands), it may be disconnected or redirected.

Why This Error Occurs#

The error stdin: is not a tty means a program tried to read input from stdin, but stdin is not connected to a TTY (i.e., there’s no interactive terminal to provide input). This happens most often when:

  • A remote command expects interactive input (e.g., a password prompt from sudo), but SSH doesn’t allocate a TTY.
  • A non-interactive command is run with TTY allocation enabled, causing a mismatch.
  • SSH is chained through intermediate machines (jump hosts), breaking TTY propagation.

Common Scenarios Where the Error Occurs#

1. Direct Remote Command Execution#

Running a command directly over SSH that requires a TTY:

ssh user@remote-server "sudo apt update"  

If sudo requires a password (or even if it’s passwordless but configured to demand a TTY), this often triggers stdin: is not a tty.

2. Multi-Hop SSH (Through a Jump Host)#

When executing commands through a jump host (e.g., ssh jump-host "ssh target-host command"), the inner SSH session may fail to inherit a TTY from the outer session:

ssh user@jump "ssh user@target sudo systemctl restart service"  

Here, the nested ssh command on jump lacks a TTY, causing the error.

3. Running Scripts or Commands That Expect a TTY#

Scripts or commands with hardcoded TTY dependencies (e.g., using read for input, or tools like top/nano run non-interactively) will fail if no TTY is available.

Root Causes of the Error#

  • SSH Defaults to Non-Interactive Mode: By default, SSH does not allocate a TTY when running remote commands (it uses “batch mode”). This is efficient for non-interactive tasks but breaks commands expecting a terminal.
  • sudo Requires a TTY: Many systems configure sudo to require a TTY for security (via requiretty in /etc/sudoers). Even passwordless sudo may fail without a TTY.
  • Chained SSH Sessions: When SSHing through a jump host, the outer SSH session may not forward the TTY to the inner session, leaving the inner command without a terminal.

Step-by-Step Solutions to Fix the Error#

Solution 1: Force TTY Allocation with -t#

The simplest fix for commands needing interactive input is to force SSH to allocate a TTY using the -t flag.

Basic Usage#

Add -t to your SSH command to allocate a pseudo-TTY:

ssh -t user@remote-server "sudo apt update"  

Now, sudo can prompt for a password via the allocated TTY, and the error disappears.

Multi-Hop SSH Scenarios#

For jump hosts, use -t on both the outer and inner SSH commands to propagate the TTY:

ssh -t user@jump-host "ssh -t user@target-host 'sudo systemctl restart service'"  
  • The outer -t allocates a TTY for the jump host session.
  • The inner -t ensures the target host session inherits the TTY.

Note: Use -tt (double -t) if the first -t isn’t sufficient (forces TTY allocation even if SSH thinks it’s unnecessary).

Solution 2: Disable TTY Allocation with -T#

If the remote command does not need a TTY (e.g., it’s non-interactive and doesn’t require input), use the -T flag to explicitly disable TTY allocation. This suppresses the stdin: is not a tty error.

Example:

ssh -T user@remote-server "ls -l /home"  

Here, ls is non-interactive, so no TTY is needed. -T tells SSH not to allocate one, avoiding the error.

Solution 3: Modify sudoers to Bypass TTY Requirements#

If sudo is the culprit (common for passwordless sudo), you can configure sudo to skip TTY checks for specific users/commands.

Step 1: Edit the sudoers File#

Use visudo (safe for editing sudoers) to modify the configuration:

sudo visudo  

Step 2: Add a Rule to Disable requiretty#

Add one of these lines to the file (replace user with your username):

  • Allow all sudo commands for user without a TTY:

    Defaults:user !requiretty  
  • Allow a specific command (e.g., apt update) without a TTY:

    Defaults!/usr/bin/apt !requiretty  

Save and exit. Now, sudo commands for user will no longer demand a TTY.

Solution 4: Use Here-Documents or Input Redirection#

For commands needing input (e.g., a password), redirect input from a here-document or file to bypass TTY requirements.

Example (with sudo password):

ssh user@remote-server "echo 'user-password' | sudo -S apt update"  
  • -S tells sudo to read the password from stdin (instead of a TTY).
  • The here-document (echo 'password' | ...) pipes the password into sudo.

Warning: Avoid hardcoding passwords in scripts! Use SSH keys or passwordless sudo for security.

Solution 5: Verify Interactive vs. Non-Interactive Commands#

Ensure the remote command truly needs a TTY. For example:

  • Interactive commands (need TTY): sudo (with password), nano, top, read prompts.
  • Non-interactive commands (no TTY needed): ls, grep, echo, systemctl status.

If you’re running a non-interactive command and still get the error, use -T (Solution 2) to disable TTY allocation.

Troubleshooting Tips#

1. Check TTY Allocation#

Run tty on the remote server to see if a TTY is allocated:

# With TTY (via -t)  
ssh -t user@remote-server "tty"  
# Output: /dev/pts/0 (or similar)  
 
# Without TTY (default or -T)  
ssh user@remote-server "tty"  
# Output: not a tty  

2. Use SSH Verbose Mode (-v)#

Add -v to SSH to debug TTY allocation:

ssh -v user@remote-server "command"  

Look for lines like:

  • debug1: Allocating pty (TTY allocated).
  • debug1: Not allocating pty (no TTY allocated).

3. Test Interactively First#

Run the command in an interactive SSH session to confirm it works:

ssh user@remote-server  
# Now run the command manually:  
sudo apt update  

If it works interactively, the issue is likely TTY allocation in non-interactive mode (use -t).

4. Check sudo Configuration#

Verify if sudo requires a TTY:

ssh user@remote-server "sudo -l" | grep requiretty  

If requiretty is listed, use Solution 3 to bypass it.

Conclusion#

The stdin: is not a tty error is a common SSH pitfall, but it’s easily fixed with the right tools:

  • Use -t to force TTY allocation for interactive commands (e.g., sudo with passwords).
  • Use -T to disable TTY allocation for non-interactive commands.
  • Modify sudoers to skip TTY checks for passwordless sudo.
  • Test TTY allocation with tty and debug with ssh -v.

By understanding whether your command needs a TTY and adjusting SSH flags accordingly, you can resolve this error and run remote commands seamlessly.

References#