cannot attach stdin to a TTY-enabled container because stdin is not a terminal — you asked Docker for a terminal with -t (usually -it), but the shell you typed it in is not giving Docker a terminal. Docker releases before 29.4 print the same refusal as the input device is not a TTY, on Windows with a hint about winpty. In a script or pipe drop -t; in Git Bash put winpty in front.

For typing into a shell inside the container, a PowerShell or Windows Terminal window runs docker exec -it as it is. For scripts, CI jobs and anything with a pipe, keep -i and leave out -t.

The error

$ docker exec -it fixes2-ops-tty sh
cannot attach stdin to a TTY-enabled container because stdin is not a terminal

Why it happens

-i keeps the container's standard input connected to yours; -t gives the process in the container a pseudo-terminal. A terminal in the container is only useful if the Docker CLI can pass your keystrokes through one, so the CLI checks whether its own standard input is a terminal and stops if it is not. -t without -i is not checked.

On Windows standard input is not a terminal in three common places: a pipe or redirect (echo ... | docker exec -it); a command runner with no console, such as a CI job, a scheduled task or an editor's task runner; and the Git Bash window when Git for Windows was installed without pseudo console support. That window, mintty, is a terminal for bash itself, but a native Windows program such as docker.exe is connected through pipes. winpty sits in between and hands docker.exe a real Windows console.

The fix

# Git Bash (mintty): winpty gives docker.exe a real console
winpty docker exec -it fixes2-ops-tty sh -c "tty > /tmp/winpty-disable_pcon"

# Scripts, pipes and CI: keep -i, drop -t
docker exec -i fixes2-ops-tty sh -c "echo ok"
echo "echo piped ok" | docker exec -i fixes2-ops-tty sh

The winpty line exited with 0 and the file it wrote inside the container read /dev/pts/0, so a terminal was allocated; for an interactive shell, end the command at sh. The two -i lines printed ok and piped ok from the same non-terminal shell that produced the error. The same docker exec -it run from a PowerShell console window also got /dev/pts/0. If you would rather not type winpty, pseudo console support in Git for Windows removes the need: on this machine it was off (MSYS=disable_pcon in C:\Program Files\Git\etc\git-bash.config), and a mintty window started with MSYS=enable_pcon ran plain docker exec -it without the error.

How it was reproduced

Docker Desktop 4.91.0 (CLI and engine 29.8.0) on Windows 11, Git for Windows 2.45.2 with mintty 3.7.1 and winpty 0.4.3, pseudo console support off. The container ran sleep 900 from the local postgres:18 image; the image does not matter, because the check is made by the Docker CLI on your side. The error appeared from Git Bash and from PowerShell run by a tool with no console, from a pipe into docker exec -it, and inside a real mintty window. The older wording was checked in the Docker CLI source: cli/streams/in.go still has it at tag v29.3.0 and has the new text at v29.4.0.

Frequently asked

What does 'the input device is not a TTY' mean in Docker?
It is the older wording of the same error, printed by Docker CLI releases before 29.4. You used -t or -it while the CLI's standard input was not a terminal. Remove -t in scripts and pipes, or prefix the command with winpty in Git Bash.
Should I use docker exec -i or -it in a script?
Use -i. It passes piped or redirected input to the container without asking for a terminal. Use -it only when a person is typing into the container from a real terminal window.
Why does docker exec -it work in PowerShell but not in Git Bash?
A PowerShell or Windows Terminal window gives docker.exe a real Windows console. Git Bash's mintty window, without pseudo console support, connects native Windows programs through pipes, so docker.exe sees no terminal. Prefix the command with winpty or enable pseudo console support in Git for Windows.

More decoded errors in the Fixes category, and if containers are new to you, start with Docker explained for beginners.