skip to content

questions

5

After a container stops, where do you find the exit code it reported, and what do the values 0 and 1 tell you about what happened?

level: juniorimportance: must knowfreq 62%

answer

  1. Container = PID 1; PID 1 exits, container exits
  2. `docker ps -a` STATUS → `Exited (N)`
  3. `docker inspect --format '{{.State.ExitCode}}'`
  4. 0 = success; 0 on a server = suspicious
  5. 1 = generic app error → read `docker logs`

basics

~20 s

docker ps -a shows Exited (N) in the STATUS column, and docker inspect --format '{{.State.ExitCode}}' <container> gives the number. 0 means the main process finished successfully; any non-zero value means it failed — 1 is the generic "the application errored" code.

solid answer

~50 s

A container's exit code is the exit status of its **main process (PID 1)**. When that process ends, the container ends, and the code is recorded. Two places to read it: - `docker ps -a` → STATUS column shows `Exited (1) 30 seconds ago`. - `docker inspect --format '{{.State.ExitCode}}' <container>` → just the number (also `.State.Error`, `.State.OOMKilled`, `.State.FinishedAt`). `0` = the process completed successfully; for a long-running server, exiting 0 is still suspicious because it means it decided to stop. `1` is the generic application-error code — a config parse failure, an unhandled exception, an explicit `exit 1` in an entrypoint script. Non-zero says "something went wrong" but not what, so the code is only step one: pair it with `docker logs <container>` for the actual message. Codes in the 125–127 and 128+ ranges are special and have specific meanings beyond "the app failed".

go deeper

for a junior

Know that the container's code is PID 1's code, that docker ps -a and docker inspect show it, and that 0 = success, non-zero = failure.

for a middle

Add why a server exiting 0 is a bug (daemonizing/foreground process), and that 1 is generic so logs are the real diagnosis.

for a senior

Frame the exit code as the input to restart policies and CI gating, and mention docker wait plus .State.Error/.State.FinishedAt when scripting or triaging.

for a principal

Talk about making exit codes meaningful as a platform contract — services that exit non-zero on unrecoverable config errors, never daemonize, and never exit 0 on failure, so restart and alerting policy can be uniform.

## What an exit code is Every process on Linux ends with an 8-bit **exit status**, a number from 0 to 255 that it hands back to whoever started it. By universal convention `0` means success and anything non-zero means failure. In a shell you read it as `$?`. A container is a wrapper around one **main process** — PID 1 inside the container's namespace, the thing your `ENTRYPOINT`/`CMD` launched. The container's lifetime is that process's lifetime: when PID 1 exits, the container transitions to the `exited` state regardless of whether other processes are still alive inside it. The exit status of that process becomes the container's exit code, and the daemon stores it in the container's state record. ## Where to read it A stopped container still exists (with its filesystem, logs, and state) until you `docker rm` it, so the code survives the process. - `docker ps -a` lists stopped containers too; the STATUS column reads `Exited (1) 2 minutes ago`. This is the quickest look. - `docker inspect --format '{{.State.ExitCode}}' <container>` prints only the number, which is what you want in scripts. - The whole state block is worth knowing: `docker inspect --format '{{json .State}}' <container>` gives `Status`, `ExitCode`, `Error`, `OOMKilled`, `StartedAt`, `FinishedAt`. `Error` often carries the daemon's own message when the container never really started. - `docker wait <container>` blocks until the container stops and then prints its exit code — handy in CI scripts. - `docker run` in the foreground (without `-d`) passes the container's exit code through as the exit code of the `docker run` command itself, so `echo $?` after it works exactly as you'd expect. ## Reading 0 `0` means the main process ran to completion and reported success. For a batch job — a migration, a test run, a one-shot CLI — that is the outcome you wanted, and it is why CI pipelines gate on `docker run ... && next-step`. For a **long-running service**, exit 0 is not automatically good news. It means the server decided to stop on its own: it finished reading stdin and quit, it forked into the background and the foreground process returned (a classic mistake — the daemon "started" and PID 1 immediately exited), or it received a shutdown signal and its handler chose to `exit(0)`. A web server that shows `Exited (0)` seconds after launch is almost always a startup bug, not a clean run. ## Reading 1 `1` is the catch-all failure code. Language runtimes use it for an uncaught exception; shells use it for a failed command; most programs use it for "bad configuration, cannot continue". Concretely you'll see it when an environment variable is missing, a config file fails to parse, a required port is already bound, a database connection is refused at boot, or an entrypoint script hits `set -e` and a command failed. Because `1` is generic, it tells you *that* the application failed, never *why*. The next command is always `docker logs <container>` (add `--tail 50` on a noisy container). Applications that want to be more informative define their own codes — anything from 2 to 124 is fair game for an application to use for its own meanings, and some tools do (curl, for instance, has dozens). ## Why the code matters operationally The exit code is the input to everything downstream: - **Restart behaviour**: `--restart=on-failure` restarts only for non-zero exits, so a process that exits 0 by mistake will never be restarted. - **CI/CD**: a build step's pass/fail is literally the container's exit code. - **Orchestrators** surface the same number when they report a crash, so the vocabulary transfers. ## Ranges to be aware of Docker reserves some values so it can report failures that are the *daemon's* problem rather than the app's: `125` (the `docker run` invocation itself failed), `126` (the command was found but is not executable), `127` (the command was not found). And any container killed by a signal reports `128 + signal number` — `137` for SIGKILL (9), `143` for SIGTERM (15). So when a code looks strange, check whether it falls in one of those buckets before blaming application logic.

  • Your web server container shows `Exited (0)` two seconds after `docker run -d`. What is the likely cause?
    The main process almost certainly daemonized or self-terminated: it forked a background worker and the foreground process returned success, or it ran a command that completed rather than a server that blocks. Containers need a foreground process — start the server with its no-daemon/foreground flag (for example `nginx -g 'daemon off;'`). Check `docker logs` to confirm it printed a normal startup-then-exit sequence rather than an error.
  • Does a non-zero exit code delete the container or its logs?
    No. A stopped container keeps its writable layer, its configuration, and its log file until you run `docker rm` (or started it with `--rm`, which removes it as soon as it exits). That is why you can still run `docker logs` and `docker inspect` on an exited container — and why using `--rm` on a crashing container makes debugging much harder.

saying these in an interview costs you the question

  • Thinking the exit code belongs to the whole container's process tree rather than to PID 1 specifically
  • Assuming exit 0 always means healthy, even for a server that stopped seconds after start
  • Treating exit code 1 as diagnostic in itself instead of immediately reading the logs
  • Running crashing containers with `--rm` and then wondering why there is nothing left to inspect

context

open as a page

A stopped container reports exit code 137, and another reports 143. Explain Docker's "128 + N" convention and say which signal produced each of those two codes.

level: middleimportance: must knowfreq 72%

basics

~20 s

When a process is terminated by a signal rather than exiting on its own, the reported status is 128 plus the signal number. 137 = 128 + 9 = SIGKILL (force kill, often an out-of-memory kill). 143 = 128 + 15 = SIGTERM (a polite stop request the process did not survive).

open as a page

A container stopped with exit code 137. How do you determine whether the kernel's out-of-memory killer did it or something else sent SIGKILL, and what evidence do you collect?

level: seniorimportance: must knowfreq 58%

basics

~20 s

137 only says "killed by SIGKILL". Check docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}}' <container>: true means the kernel out-of-memory killer fired. If it is false, look for a stop that timed out into SIGKILL, a docker kill, or a host-level kill — using timestamps, daemon logs, and dmesg.

open as a page

`docker run` can fail with status 125, 126, or 127. What does each of those three values mean, and what kind of mistake causes each?

level: middleimportance: should knowfreq 52%

basics

~20 s

125 = the docker run command itself failed (bad flag, daemon or image-config error) — no container process ever ran. 126 = the command was found but could not be executed (not executable, bad format). 127 = the command was not found inside the image (typo, missing binary, wrong PATH).

open as a page

Two services are stopped the same way. One records exit code 143 and the other records 0. What accounts for the difference, and which outcome do you want in production?

level: middleimportance: should knowfreq 48%

basics

~20 s

143 means the process was killed by SIGTERM's default action — it ran no shutdown code. 0 means the process caught SIGTERM, shut down on its own terms, and exited successfully. In production you want 0: it proves graceful shutdown actually executed.

open as a page