The 'input device is not a TTY' error occurs when Docker commands include the -t flag (which requests a pseudo-terminal) but are run in a non-interactive environment like CI/CD pipelines or automated scripts. Remove the -t flag or use the -T flag with docker-compose exec.
The "the input device is not a TTY" error occurs when Docker tries to allocate a pseudo-terminal (TTY) but the environment running the command doesn't have one available. A TTY (teletypewriter) is a terminal interface that allows interactive input and output between you and a program. When you use the `-t` flag with `docker run` or `docker exec`, Docker attempts to allocate a pseudo-TTY for the container. However, this requires that Docker itself is running in a TTY environment. In non-interactive environments like CI/CD pipelines (GitHub Actions, Jenkins, GitLab CI), cron jobs, or when piping commands, there is no TTY available. When Docker detects this mismatch - you're asking for a TTY but running in an environment without one - it throws this error to alert you that interactive features won't work as expected.
If you don't need an interactive terminal, simply remove the -t flag from your command:
# Instead of this (fails without TTY):
docker run -it myimage /bin/sh
# Use this (works without TTY):
docker run -i myimage /bin/sh
# Or if you don't need any interactivity:
docker run myimage /bin/sh -c "your-command"The -i (interactive) flag keeps STDIN open without requiring a TTY, which is sufficient for most automated use cases.
For docker-compose exec, use the -T flag to disable pseudo-TTY allocation:
# Instead of this:
docker-compose exec myservice sh -c "echo hello"
# Use this:
docker-compose exec -T myservice sh -c "echo hello"The -T flag explicitly tells docker-compose not to allocate a TTY, making the command work in non-interactive environments.
For docker compose (V2), the same flag works:
docker compose exec -T myservice sh -c "echo hello"In your CI/CD configuration files, ensure Docker commands don't use the -t flag:
GitHub Actions example:
steps:
- name: Run tests in container
run: |
docker run -i myimage npm test
docker-compose exec -T app ./run-tests.shJenkins Pipeline example:
sh 'docker run -i myimage npm test'
sh 'docker-compose exec -T app ./run-tests.sh'GitLab CI example:
test:
script:
- docker run -i myimage npm test
- docker-compose exec -T app ./run-tests.shWhen piping input to Docker, the -t flag won't work because STDIN comes from the pipe, not a terminal:
# This fails:
echo "ls -la" | docker run -it alpine sh
# This works (remove -t, keep -i):
echo "ls -la" | docker run -i alpine shFor commands that read from STDIN:
# Pass file contents to container:
cat script.sh | docker run -i alpine sh
# Or use redirection:
docker run -i alpine sh < script.shGit Bash on Windows uses mintty, which doesn't provide a native Windows TTY. Use one of these solutions:
Option 1: Use winpty prefix:
winpty docker run -it alpine shOption 2: Use PowerShell instead:
PowerShell provides proper TTY support on Windows.
docker run -it alpine shOption 3: Use Windows Terminal:
Windows Terminal with Git Bash provides better TTY compatibility.
Option 4: Configure Git Bash:
Add to your ~/.bashrc:
# Automatically use winpty for docker commands
alias docker='winpty docker'In scripts that run both interactively and in CI, detect TTY availability:
#!/bin/bash
# Check if running in a TTY
if [ -t 0 ]; then
# Interactive - use -it
docker run -it myimage /bin/sh
else
# Non-interactive - use -i only
docker run -i myimage /bin/sh
fiOr use a one-liner:
docker run $([ -t 0 ] && echo "-it" || echo "-i") myimage /bin/shThis makes your scripts work in both environments without modification.
### Understanding -i vs -t Flags
The -i and -t flags serve different purposes:
- `-i` (interactive): Keeps STDIN open even if not attached. Required if you want to send input to the container.
- `-t` (tty): Allocates a pseudo-TTY. Provides terminal features like colored output, command history, and proper signal handling.
When combined as -it, you get a full interactive terminal experience. However, -t requires a real TTY on the host side.
### TTY Detection in Docker
Docker checks if its own STDIN is a TTY before allocating a pseudo-TTY:
# Check if current shell has a TTY
if [ -t 0 ]; then
echo "STDIN is a TTY"
else
echo "STDIN is not a TTY"
fi
# Check if STDOUT is a TTY
if [ -t 1 ]; then
echo "STDOUT is a TTY"
fi### Common CI/CD Environment Variables
Many CI systems set environment variables you can check:
# GitHub Actions
if [ "${GITHUB_ACTIONS}" = "true" ]; then
DOCKER_FLAGS="-i"
else
DOCKER_FLAGS="-it"
fi
# Jenkins
if [ -n "${JENKINS_HOME}" ]; then
DOCKER_FLAGS="-i"
else
DOCKER_FLAGS="-it"
fi
# Generic CI detection
if [ "${CI}" = "true" ]; then
DOCKER_FLAGS="-i"
else
DOCKER_FLAGS="-it"
fi
docker run ${DOCKER_FLAGS} myimage /bin/sh### Makefile Considerations
In Makefiles, commands don't run in a TTY by default:
# This may fail with TTY error
shell:
docker run -it myimage /bin/sh
# Use this instead
shell:
docker run -i myimage /bin/sh
# Or detect TTY availability
shell:
@if [ -t 0 ]; then \
docker run -it myimage /bin/sh; \
else \
docker run -i myimage /bin/sh; \
fi### Why Some Commands Need TTY
Certain commands require a TTY to function properly:
- Interactive shells (bash, zsh, sh in interactive mode)
- Text editors (vim, nano)
- Programs using ncurses (htop, less with certain options)
- Commands that prompt for passwords
For these use cases in CI, consider alternatives:
- Use non-interactive modes (bash -c "command" instead of interactive bash)
- Set passwords via environment variables or config files
- Use expect scripts for automation if interaction is truly required
dockerfile parse error line 5: unknown instruction: RRUN
How to fix 'unknown instruction' Dockerfile parse error in Docker
Error response from daemon: manifest for nginx:nonexistent not found: manifest unknown: manifest unknown
How to fix 'manifest for image:tag not found' in Docker
Error response from daemon: invalid reference format: repository name must be lowercase
How to fix 'repository name must be lowercase' in Docker
Error response from daemon: No such image
How to fix 'No such image' in Docker
Error response from daemon: Container is not running
How to fix 'Container is not running' when using docker exec