This SSH warning occurs when you run commands with piped or redirected input without allocating a terminal. The fix involves using SSH flags like -t, -tt, or -T depending on your use case.
A pseudo-terminal (pty) is a virtual device that emulates a physical terminal, allowing programs to interact with users as if they're running on a real terminal. When you execute SSH commands with stdin redirected from a pipe or file, SSH expects an interactive login session but realizes that stdin is not actually a terminal. This mismatch causes the warning. The error typically appears when running commands from scripts, CI/CD systems, or when piping data into remote commands.
Force SSH to allocate a pseudo-terminal even when stdin is not a terminal:
ssh -t user@hostname 'sudo apt-get update'
ssh -t user@hostname 'vim /etc/config'The -t option tells SSH to allocate a pty on the remote machine, which is necessary for interactive commands that need a terminal.
For commands with stdin redirection that need stronger terminal allocation:
ssh -tt user@hostname 'cat file.txt' < input.txtThe -tt option (double -t) forces tty allocation even without a local tty, useful for stdin redirection scenarios.
For commands that don't need a terminal, disable pty allocation entirely:
ssh -T user@hostname 'ls -l /home'
ssh -T user@hostname 'grep error logfile.txt'The -T option explicitly tells SSH not to allocate a pty on the remote machine. This is ideal for simple, non-interactive commands that don't require terminal features.
When piping scripts or commands, explicitly use bash -s to read from stdin without needing a pty:
# Pipe a local script to remote bash
cat local_script.sh | ssh user@hostname 'bash -s'
# Use here-document syntax
ssh user@hostname 'bash' << 'EOF'
uptime
hostname
pwd
EOFThis approach tells SSH to run a non-interactive shell that reads commands from stdin, bypassing the need for a pty entirely.
For tools like Ansible or CI/CD systems, configure SSH to request a terminal:
In ~/.ssh/config:
Host remote-server
HostName example.com
User ubuntu
RequestTTY yesOr in Ansible playbooks:
- name: Run remote command
ansible.builtin.shell: |
remote_command_here
delegate_to: remote_server
vars:
ansible_ssh_extra_args: '-tt'This ensures terminal allocation is configured at the SSH config level rather than per-command.
If the command actually works but the warning is annoying, use quiet mode:
ssh -q user@hostname 'some_command'The -q option enables quiet mode and suppresses the warning message. Use this only if the command executes successfully; it can mask real errors.
The choice between -t, -tt, and -T depends on your specific use case. Use -t or -tt when you need interactive terminal features (sudo prompts, terminal-based editors, menu systems). Use -T for simple, non-interactive commands. For scripts and automation, bash -s is often the cleanest solution. In Jenkins environments, ensure the Jenkins user can connect to SSH hosts without host key verification blocking the connection; this is a common culprit. Consider using SSH key-based authentication with forced commands in authorized_keys if you're automating deployments. For rootless SSH access, verify that your user has proper group membership and permissions on the remote system.
Load key "/home/user/.ssh/id_rsa": invalid format
How to fix 'Load key invalid format' in SSH
Bad owner or permissions on /home/user/.ssh/config
How to fix "Bad owner or permissions on .ssh/config" in SSH
Error connecting to agent: Connection refused
How to fix "Error connecting to agent: Connection refused" in SSH
Connection closed by UNKNOWN port 65535
How to fix 'Connection closed by UNKNOWN port 65535' in SSH
Offending ECDSA key in /home/user/.ssh/known_hosts:line
How to fix "Offending ECDSA key in known_hosts" in SSH