Meta description: Docker container exits with code 0? I show the exact commands I use to diagnose and fix it fast, with production-tested solutions from real debugging.
Last updated: July 3, 2026
The first time a container of mine exited with code 0 right after docker run, I assumed something had crashed — except code 0 means “successful exit,” which made it even more confusing. No errors, no stack trace, just a container that ran and stopped in under a second. If you’ve hit this, you’re not dealing with a crash; you’re dealing with a process that finished doing what you told it to do, faster than you expected.
Here’s how I track down the real cause every time this happens, with the actual commands and error patterns I’ve run into across dozens of containers.
TL;DR
- Exit code 0 means the container’s main process finished normally — it’s not a crash, it’s usually a missing foreground process or a misconfigured
CMD/ENTRYPOINT. - The most common cause is running a container without a long-running foreground process (no web server, no daemon, nothing keeping PID 1 alive).
docker logs,docker inspect, and running the image interactively withdocker run -it --entrypoint share the three tools I reach for first.
Why Does a Docker Container Exit Immediately with Code 0?
Docker containers stay alive only as long as PID 1 — the main process — keeps running. Unlike a VM, there’s no init system keeping things alive in the background by default. If your CMD runs a script that finishes executing, or starts a background process with & and then exits, the container exits right along with it, and Docker reports whatever exit code that process returned. Code 0 specifically means it exited cleanly, which is often the most confusing case because there’s no obvious error to grep for.
I’ve seen this trip up teams migrating from VM-based deployments the most, since the mental model of “a server that just stays running” doesn’t map directly onto how container processes work.
Prerequisites
- Docker Engine 24+ (I’m running
Docker version 26.1.3at the time of writing) - Basic familiarity with
Dockerfilesyntax (CMD,ENTRYPOINT) - A container that’s exiting unexpectedly to debug against
Step-by-Step Implementation
Step 1: Confirm the Exit Code and Reason
docker ps -a
Look at the STATUS column — you’ll see something like Exited (0) 3 seconds ago. Then get more detail:
docker inspect <container_id> --format '{{.State.ExitCode}} - {{.State.Error}}'
Pro Tip: If
.State.Erroris empty and the exit code is 0, that’s your confirmation this isn’t a crash — the process really did finish on its own.
Step 2: Check the Logs
docker logs <container_id>
This is where I usually spot the real story. In one case, my logs showed:
Starting setup script...
Setup complete.
…and nothing else. That was the entire lifetime of the container — the CMD was a shell script that ran a one-time setup task and had nothing left to execute, so the container exited the moment the script finished.
Step 3: Inspect the CMD and ENTRYPOINT
docker inspect <image_name> --format '{{.Config.Cmd}} | {{.Config.Entrypoint}}'
The most common broken pattern I see is a Dockerfile like this:
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD npm run build && npm start &
That trailing & backgrounds npm start, so the shell running CMD exits immediately after kicking it off — and PID 1 exits with it, taking the container down even though npm start briefly existed in the background.
Step 4: Run the Image Interactively to Reproduce
docker run -it --entrypoint sh my-image:latest
This drops you into a shell inside the image without running the default CMD, so you can manually run the intended startup command and watch exactly where it stops.
/app # npm start
In my case, this immediately surfaced the real problem:
Error: Cannot find module 'express'
npm start exited with code 0 due to shell wrapper swallowing the error
The npm start script itself was failing, but a wrapper shell script upstream was catching the failure and exiting 0 anyway — masking the real issue.
Step 5: Fix the Foreground Process
The fix depends on the root cause, but these are the three I hit most often:
Missing foreground process:
# Before
CMD ["/app/setup.sh"]
# After — keep a long-running process as PID 1
CMD ["node", "server.js"]
Backgrounded process with &:
# Before
CMD npm run build && npm start &
# After — run in foreground, no trailing &
CMD ["sh", "-c", "npm run build && npm start"]
Swallowed errors in a wrapper script:
#!/bin/sh
set -e # exit immediately on any command failure instead of continuing silently
npm start
Security Note: If you’re using a wrapper entrypoint script, always add
set -eat the top. Without it, a failed command partway through the script won’t stop execution, and you’ll get misleading exit codes that hide real failures.
[INTERNAL LINK: related article]
Real-World Tips I Use in Production
Once the container stays up correctly, these are the habits that keep it that way:
- I always test images locally with
docker run -it --entrypoint shbefore pushing to a registry, specifically to catch silent exits like this. - For any container meant to run a daemon, I check that the last line of my entrypoint script actually
execs the long-running process, so it replaces the shell as PID 1 instead of running as a child that can be orphaned on shutdown. - I’ve started using
HEALTHCHECKin my Dockerfiles specifically because it surfaces “container is up but not actually healthy” cases that a bare exit-code check won’t catch.
Common Errors and How I Fixed Them
Error: Container exits 0 with empty logs. Cause: CMD was a sleep 5 placeholder I forgot to replace during local testing, and it made it into a build. Fix: Replaced it with the actual application start command.
Error: Exit 0 despite npm start throwing an unhandled exception. Cause: A supervisor wrapper script was catching non-zero exits and returning 0 regardless. Fix: Removed the wrapper’s || exit 0 fallback and let real exit codes propagate.
Error: Container works with docker run but exits immediately under docker-compose up. Cause: docker-compose.yml had a command: override that pointed to a script that no longer existed after a refactor. Fix: Updated the command: field to match the current entrypoint script path.
FAQ
Q: What does exit code 0 mean in a Docker container? A: It means the container’s main process (PID 1) completed and exited normally, without an error — the container isn’t crashing, it’s just not staying alive.
Q: Why does my container exit immediately even though the app works when I run it locally? A: It’s usually because the containerized command isn’t running as a foreground, long-running process, or an error is being silently swallowed by a wrapper script.
Q: How do I keep a Docker container running after the main process finishes? A: You generally shouldn’t force it to stay alive artificially — instead, make sure your CMD or ENTRYPOINT runs the actual long-running process, like a web server or daemon.
Q: What’s the difference between exit code 0 and exit code 1 in Docker? A: Exit code 0 means the process finished successfully; exit code 1 (or other non-zero codes) means it exited due to an error or failure condition.
Q: How can I debug a Docker container that exits before I can attach a shell? A: Override the entrypoint with docker run -it --entrypoint sh <image> so you get a shell without the default CMD running, then manually execute the startup command to watch it fail.
Conclusion
An exit code of 0 is almost never a mystery once you check three things: the logs, the actual CMD/ENTRYPOINT, and whether a foreground process is really staying alive as PID 1. Most of the time it’s a one-line fix in the Dockerfile. If you’ve run into a stranger variant of this — especially with docker-compose or Kubernetes-managed pods — I’d like to hear about it in the comments.
[SOURCE: https://docs.docker.com/reference/dockerfile/#cmd] [SOURCE: https://docs.docker.com/engine/reference/commandline/inspect/]
About the Author
I’m a senior software engineer with over 8 years of experience in backend development and DevOps, having containerized and deployed dozens of production services with Docker and Kubernetes. I write about the real debugging workflows I use day to day, not just the theory. If this saved you time, sharing it helps other developers stuck on the same exit code find it faster
