How do you troubleshoot a container that exits immediately after starting?
Quick Answer
Check docker logs <container> first — the application likely printed an error explaining exactly why it exited. Then check the exit code via docker inspect or docker ps -a: a clean exit code 0 suggests the main process simply finished and returned, often meaning the CMD/ENTRYPOINT isn't actually a long-running process, while a non-zero code suggests an application-level error. If logs are unhelpfully empty, run the container interactively with an overridden command (docker run -it myapp sh) to poke around before the normal command would run.
Detailed Answer
Step 1: check the logs — the fastest, most direct signal
docker logs my-container
The application itself often printed a clear explanation of what went wrong before exiting — a missing environment variable, a failed database connection, a syntax error, a missing file. Always check this first, before any deeper investigation.
Step 2: check the exit code
docker ps -a
# STATUS: Exited (0) 2 seconds ago <- clean exit
# or:
# STATUS: Exited (1) 2 seconds ago <- error exit
docker inspect my-container --format='{{.State.ExitCode}}'
- Exit code 0, a clean exit — often means the container's main process simply ran to completion and returned normally. For a container that's supposed to be a long-running server, this often points to a misunderstanding of what the
CMD/ENTRYPOINTactually runs — for example, accidentally running a one-shot setup script instead of the actual server process, or using a shell script that doesn't end with a command that blocks or keeps running. - A non-zero exit code — indicates an actual application-level error. The specific code sometimes has a recognizable meaning:
137(128+SIGKILL) is often an OOMKill, and1is a generic catch-all application error in most conventions. But the logs from Step 1 usually tell you much more directly than the number alone.
Step 3: if logs are empty or unhelpful, run interactively with an overridden command
docker run -it --entrypoint sh myapp:1.0
Overriding the ENTRYPOINT with an interactive shell lets you explore the image's filesystem before the normal startup command would even run. This is useful for checking that expected files or configuration are actually present, testing whether a command runs correctly when invoked manually, or investigating an environment where the real command fails too fast or too silently to diagnose any other way.
Common specific root causes
- Missing or incorrect environment variables the application requires at startup, causing it to fail an early validation check and exit immediately — often with a helpful error message if the application validates configuration properly, or a much less helpful generic crash if it doesn't.
- A missing dependency file — a config file, certificate, or other resource expected at a specific path that wasn't actually included in the image or mounted correctly.
- Incorrect
CMD/ENTRYPOINT— pointing at a script or binary that doesn't exist at that path inside the image, or isn't marked executable. - The application genuinely isn't meant to be long-running — for example, accidentally treating a one-shot script/tool's image as if it should run as a persistent service.
- A crash during the application's own startup sequence — an unhandled exception during initialization. Often the most common real cause, and exactly what Step 1's log check is meant to surface directly.
Verifying the CMD/ENTRYPOINT is actually what you expect
docker inspect myapp:1.0 --format='{{.Config.Cmd}} {{.Config.Entrypoint}}'
Occasionally the actual configured command differs from what you expect — this can happen when a base image's own ENTRYPOINT unexpectedly combines with your own CMD in a way you didn't intend. Confirming exactly what's configured to run is a useful check before assuming the problem lies elsewhere. Working through logs, then exit code, then an interactive override, in that order, resolves most of these issues without needing to guess at more exotic causes first.