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 with docker run -it --entrypoint sh are 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.3 at the time of writing)
  • Basic familiarity with Dockerfile syntax (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.Error is 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 -e at 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 sh before 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 HEALTHCHECK in 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