How to fix Container process (PID 1) exited unexpectedly in Docker
This error occurs when the main process running inside a Docker container (PID 1) terminates unexpectedly, causing the container to stop. The fix typically involves ensuring your application runs in the foreground, handles signals properly, and uses an init process when needed.
Quick fix
Fixes Container process (PID 1) exited unexpectedly
# View full logs from exited container
docker logs <container_name_or_id>
# View last 50 lines with timestamps
docker logs --tail 50 --timestamps <container_name_or_id>
# Follow logs in real-time (useful during debugging)
docker logs -f <container_name_or_id>- Check container logs for error messages
- Inspect the container exit code and state
- Use exec form for CMD and ENTRYPOINT
- Ensure the process runs in foreground mode
# View full logs from exited containerdocker logs <container_name_or_id># View last 50 lines with timestampsdocker logs --tail 50 --timestamps <container_name_or_id># Follow logs in real-time (useful during debugging)docker logs -f <container_name_or_id>Container process (PID 1) exited unexpectedly
What this error means
In Docker, each container has a main process that runs as PID 1 (Process ID 1). Unlike traditional Linux systems where PID 1 is the init system (systemd, init, etc.), in containers PID 1 is your application itself. When this process exits for any reason, the entire container stops immediately. This error indicates that your container's main process terminated when it was expected to keep running. The container lifecycle is directly tied to this process - there is no background daemon keeping the container alive. If PID 1 exits with code 0, Docker considers it a successful completion. If it exits with any other code, Docker reports it as an unexpected exit. Understanding PID 1 behavior is crucial because it differs from regular processes: PID 1 has special signal handling rules in Linux. By default, signals like SIGTERM are ignored unless explicitly handled, which can cause issues with graceful shutdowns.
Typical symptoms
- Container starts and immediately stops (exits within seconds)
- docker ps shows container with status 'Exited' instead of 'Up'
- docker logs shows the application starting but then nothing else
- Container works with docker run -it but exits with docker run -d
- Application logs indicate successful startup but container still exits
- docker inspect shows ExitCode is non-zero (commonly 1, 137, or 139)
- Container restarts repeatedly when using restart: always policy
- docker stop takes exactly 10 seconds (timeout waiting for SIGTERM)
Common causes
- Main process completed its task and exited normally (not designed to run continuously)
- Application is running in background/daemon mode instead of foreground
- Shell script entrypoint exits after spawning a background process
- Application crashed due to an unhandled exception or error
- Process was killed by the kernel (OOM killer) due to memory limits
- Signal handling not configured - SIGTERM ignored because process is PID 1
- ENTRYPOINT or CMD misconfigured, causing wrong process to run as PID 1
- Shell form CMD runs /bin/sh as PID 1, which exits when child process completes
- Missing dependencies or configuration files causing immediate crash
- Segmentation fault or other critical runtime error
How to fix "Container process (PID 1) exited unexpectedly"
First, examine what happened before the container exited. The logs often reveal the root cause:
# View full logs from exited container
docker logs <container_name_or_id>
# View last 50 lines with timestamps
docker logs --tail 50 --timestamps <container_name_or_id>
# Follow logs in real-time (useful during debugging)
docker logs -f <container_name_or_id>Look for error messages, stack traces, or any indication of why the process terminated. If the logs are empty, the process likely crashed before producing any output.
The exit code provides valuable information about why the container stopped:
# Get detailed container state including exit code
docker inspect --format='{{.State.ExitCode}} {{.State.Error}}' <container_id>
# Get full state information
docker inspect --format='{{json .State}}' <container_id> | jqCommon exit codes:
- 0: Process exited successfully (completed its task)
- 1: General application error
- 126: Command cannot execute (permission problem)
- 127: Command not found
- 137: Killed by SIGKILL (often OOM killer, exit code = 128 + 9)
- 139: Segmentation fault (exit code = 128 + 11)
- 143: Killed by SIGTERM (exit code = 128 + 15)
For OOM issues, also check:
docker inspect --format='{{.State.OOMKilled}}' <container_id>One of the most common causes is using shell form instead of exec form for CMD or ENTRYPOINT. Shell form runs your command as a child of /bin/sh, which causes signal handling problems.
Incorrect (shell form):
CMD python app.py
# This runs: /bin/sh -c "python app.py"
# /bin/sh is PID 1, python is a child processCorrect (exec form):
CMD ["python", "app.py"]
# This runs: python app.py directly as PID 1
# Python receives signals directlyThe exec form (JSON array syntax) ensures your application runs directly as PID 1, receiving signals properly. Always use exec form unless you specifically need shell features.
Many applications default to daemon mode, which backgrounds the process and causes the foreground process to exit. You must configure your application to run in the foreground.
Common examples:
# Nginx - use daemon off
CMD ["nginx", "-g", "daemon off;"]
# Apache httpd - use FOREGROUND
CMD ["httpd", "-D", "FOREGROUND"]
# PostgreSQL - runs in foreground by default
CMD ["postgres"]
# Redis - runs in foreground by default
CMD ["redis-server"]
# Node.js - runs in foreground by default
CMD ["node", "server.js"]Avoid these patterns:
# BAD - backgrounds the process
CMD ["sh", "-c", "nginx &"]
# BAD - nohup often causes issues
CMD ["nohup", "python", "app.py"]If using a shell script as your entrypoint, ensure it keeps the main process in the foreground and properly handles the exec handoff:
Problematic entrypoint.sh:
#!/bin/bash
# Setup tasks
echo "Starting application..."
python app.py & # BAD: backgrounds the process
echo "Started" # Script exits here, container stopsFixed entrypoint.sh:
#!/bin/bash
set -e
# Setup tasks (run before main process)
echo "Running initialization..."
# Use exec to replace shell with the main process
# Now python becomes PID 1 and receives signals directly
exec python app.pyThe exec command replaces the shell process with your application, making it PID 1. Without exec, the shell remains PID 1 and your app runs as a child process.
Docker's --init flag adds a tiny init process (tini) as PID 1, which properly forwards signals and reaps zombie processes:
# Run container with init process
docker run --init -d myimage
# In docker-compose.yml
services:
myapp:
image: myimage
init: trueThis is especially useful when:
- Your application doesn't handle SIGTERM properly
- You're running multiple processes in a container
- You see zombie processes accumulating
- docker stop takes the full 10-second timeout
Alternatively, add tini to your Dockerfile:
# Install tini
RUN apt-get update && apt-get install -y tini
# Use tini as entrypoint
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["python", "app.py"]If you cannot use --init, implement signal handling in your application code:
Python example:
import signal
import sys
def handle_sigterm(signum, frame):
print("Received SIGTERM, shutting down gracefully...")
# Cleanup code here
sys.exit(0)
signal.signal(signal.SIGTERM, handle_sigterm)
signal.signal(signal.SIGINT, handle_sigterm)
# Your main application codeNode.js example:
process.on('SIGTERM', () => {
console.log('Received SIGTERM, shutting down gracefully...');
// Cleanup code here
process.exit(0);
});
process.on('SIGINT', () => {
console.log('Received SIGINT, shutting down gracefully...');
process.exit(0);
});Bash script example:
#!/bin/bash
trap 'echo "Caught SIGTERM"; exit 0' TERM
trap 'echo "Caught SIGINT"; exit 0' INT
# Your main logic here
while true; do
# Do work
sleep 1
doneTo investigate what's happening inside the container, run it interactively:
# Override entrypoint to get a shell
docker run -it --entrypoint /bin/sh myimage
# Or /bin/bash if available
docker run -it --entrypoint /bin/bash myimage
# Once inside, manually run your application
./entrypoint.sh
# or
python app.pyThis lets you:
- Check if required files exist
- Verify environment variables are set correctly
- Test the application startup manually
- See error messages that might not appear in logs
For containers that exit immediately:
# Keep container running with tail
docker run -d myimage tail -f /dev/null
# Then exec into it
docker exec -it <container_id> /bin/shIf your container is being killed by the OOM (Out of Memory) killer, you'll see exit code 137:
# Check if container was OOM killed
docker inspect --format='{{.State.OOMKilled}}' <container_id>
# Check kernel logs for OOM messages (on the host)
dmesg | grep -i "killed process"Solutions:
1. Increase memory limit:
docker run -m 2g myimage
# docker-compose.yml
services:
myapp:
image: myimage
deploy:
resources:
limits:
memory: 2G2. Optimize application memory usage
3. Add swap (not recommended for production):
docker run -m 1g --memory-swap 2g myimageAdvanced notes
Understanding PID 1 in Linux vs Containers
In traditional Linux, PID 1 is the init system (systemd, SysV init) which has special kernel protections - it cannot be killed by signals unless it explicitly handles them. In containers, your application becomes PID 1, inheriting these protections. This means SIGTERM and SIGINT are ignored by default unless your application registers signal handlers.
The exec vs shell form behavior
When using shell form CMD command arg1 arg2, Docker actually runs /bin/sh -c "command arg1 arg2". This means:
1. /bin/sh is PID 1
2. Your command runs as a child process
3. Signals sent to the container go to /bin/sh first
4. Shell may not forward signals to child processes
5. When the shell exits, your process becomes orphaned
Multi-process containers
If you need multiple processes in a container (not recommended but sometimes necessary), use a proper process supervisor:
# Using supervisord
COPY supervisord.conf /etc/supervisor/conf.d/
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
# Using s6-overlay (Alpine-friendly)
ADD https://github.com/just-containers/s6-overlay/releases/download/v3.1.5.0/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ENTRYPOINT ["/init"]Debugging with strace
For mysterious exits, trace system calls:
# Install strace in container, then:
docker run -it --cap-add SYS_PTRACE myimage strace -f -e trace=process python app.pyHealth checks as early warning
Use Docker health checks to detect issues before complete failure:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1Frequently asked questions
- What does "Container process (PID 1) exited unexpectedly" mean?
- In Docker, each container has a main process that runs as PID 1 (Process ID 1). ), in containers PID 1 is your application itself. When this process exits for any reason, the entire container stops immediately.
- How do I fix "Container process (PID 1) exited unexpectedly"?
- This error occurs when the main process running inside a Docker container (PID 1) terminates unexpectedly, causing the container to stop. The fix typically involves ensuring your application runs in the foreground, handles signals properly, and uses an init process when needed.
- What causes "Container process (PID 1) exited unexpectedly"?
- Main process completed its task and exited normally (not designed to run continuously) Application is running in background/daemon mode instead of foreground Shell script entrypoint exits after spawning a background process
- Is the "Container process (PID 1) exited unexpectedly" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚Docker Official Documentation
- 📝
- 📝
- 📝
- 📝
- 💬Stack Overflow - Why docker container exits immediately(Stack Overflow)
- 💬
- 📝
- 📝