Introduction
docker exec -it works only when two assumptions are true: your current shell can provide interactive stdin, and the target process can attach a pseudo-terminal. In local terminals that is usually fine. In CI jobs, remote automation, background shells, or detached service contexts, it often is not. The result is the familiar the input device is not a TTY or tty not available style failure.
Symptoms
docker exec -itfails in CI but works locally- Running the same command without
-tsucceeds - The container is healthy, but interactive shell attachment fails
- The issue appears when the command is piped, scripted, or run over a non-interactive session
Common Causes
- The current shell does not have an interactive TTY to pass through
-tis used in a pipeline or job runner where stdin is not attached- The command should be non-interactive and only needs
-ior no TTY flags at all - The target container exited or is restarting while the exec command runs
Step-by-Step Fix
- 1.Check whether your current shell is interactive
- 2.If stdin is not a real TTY,
-twill fail before the container is even the problem.
tty
test -t 0 && echo "interactive" || echo "not interactive"- 1.Retry with the minimum flag set
- 2.Remove
-tfirst. Many scripted commands need stdin but do not need a pseudo-terminal.
docker exec -i my-container sh -c 'env | sort | head'
docker exec my-container sh -c 'ls -lah /app'- 1.**Use
-itonly for real interactive sessions** - 2.Keep the pseudo-terminal only when you are actually opening an interactive shell.
docker exec -it my-container /bin/sh
docker exec -it my-container bash- 1.Adjust CI and automation commands explicitly
- 2.In CI, prefer non-interactive forms and avoid copying local terminal habits into job scripts.
```bash # Good for CI docker exec my-container php artisan migrate --force
# Better than -it in pipelines docker exec -i my-container mysql -uroot -psecret < schema.sql ```
Prevention
- Use
-itonly for human-driven interactive shells - In automation, choose
docker exec,docker exec -i, ordocker exec -tintentionally - Add simple shell interactivity checks in CI debugging scripts
- Keep local and CI command examples separate in docs and runbooks