"Pseudo-terminal will not be allocated because stdin is not a terminal": meaning and fix

SSH wanted a terminal on the server for this session, but your input is a pipe, a file or a script rather than a keyboard, so it did not create one. It is a notice and the session continues. To silence it, use -T or name the command to run. If the remote program really needs a terminal, such as sudo asking for a password, force one with -tt.

Updated . All commands run with OpenSSH 10.3 on macOS against an OpenSSH 10.0 server on Linux, with input from a pipe, from /dev/null and from a heredoc.

When it appears

You see it in two situations. You give no remote command but feed SSH from a pipe or a heredoc:

echo uname | ssh user@server
ssh user@server <<EOF
uname
EOF

Or you ask for a terminal with -t when your own input is not one, as in cron, CI or a script:

ssh -t user@server tty < /dev/null
Pseudo-terminal will not be allocated because stdin is not a terminal.
not a tty

The commands still run. The message goes to stderr, so it can look alarming in a CI log, but it is not an error and does not change the exit status.

What each option does

Results from running tty on the server with input from /dev/null:

CommandTerminal on the serverNotice printed
ssh server ttyNoNo
ssh -T server ttyNoNo
ssh -t server ttyNoYes
ssh -tt server ttyYesNo

In short, one -t asks for a terminal if your side has one, while two force it anyway.

Fix: you are running a script (most cases)

Name a program to read the script. This is the cleanest fix. It prints no notice, and it does not show the server's welcome text either:

ssh user@server bash -s <<'EOF'
uname
EOF

-T also removes the notice, but the login shell still prints the welcome message into your output:

echo uname | ssh -T user@server

The quotes around 'EOF' stop your local shell from expanding variables before they are sent.

For a single command, pass it directly:

ssh user@server uname

For quoting, heredocs and exit codes, see how to run a command over SSH.

Fix: the remote program needs a terminal

You will know it because of an error such as this one, from sudo:

sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper

Programs like top and vim have similar needs. Force a terminal:

ssh -tt user@server 'sudo systemctl restart nginx'

Be careful with -tt in scripts. With a terminal, what you send gets echoed back, line endings can change, and output comes with carriage returns. A program waiting for a key can also hang the job forever, because nobody is there to press it. For automation, a narrow sudo rule with no password and no terminal is better than -tt. See sudo over SSH.

Set it in your config

To avoid typing the flag for a host used by scripts, add it to ~/.ssh/config:

Host backup
  HostName 203.0.113.10
  RequestTTY no

The accepted values are no, yes, force and auto. They match -T, -t and -tt, with auto being the default.

Questions

Is Pseudo-terminal will not be allocated an error?

No. It is a notice on stderr. The commands still run and the exit status does not change.

What is the difference between ssh -t and ssh -tt?

-t asks for a terminal only if your own input is one. -tt forces a terminal even from a pipe or a script.

How do I hide the message in a script?

Name the command, for example ssh user@server bash -s with a heredoc, or use -T. RequestTTY no in ~/.ssh/config does the same for one host.

Sources

More in Error messages

All guides