Three facts explain almost every stopped container: its exit code, whether the kernel killed it for memory, and the last lines it logged. All three survive the crash until someone runs docker rm (or --rm was set). Crash the API with a database host that does not exist, then provoke Docker 514 's own exit codes:
docker run -d --name l3-crash -e PGHOST=nowhere l3-booknest-api:latest >/dev/null; sleep 4
docker ps -a --filter name=l3-crash --filter status=exited --format '{{.Names}} {{.Status}}'
docker inspect l3-crash --format 'exit={{.State.ExitCode}} oom={{.State.OOMKilled}}'
docker logs --tail 20 l3-crash 2>&1 | head -1; docker rm l3-crash >/dev/null
docker run --rm --nosuchflag alpine:3 2>/dev/null; echo "exit=$?"
docker run --rm alpine:3 /etc 2>/dev/null; echo "exit=$?"
docker run --rm alpine:3 nosuchcmd 2>/dev/null; echo "exit=$?"l3-crash Exited (1) 3 seconds ago exit=1 oom=false Failed to start BookNest API Error: getaddrinfo ENOTFOUND nowhere exit=125 exit=126 exit=127
Exit code 1 with oom=false means the application chose to exit, and the log says why. Codes above 128 mean a signal killed the process (the code minus 128 is the signal's number), and 125-127 come from Docker itself:
| Exit code | Meaning | Typical cause |
|---|---|---|
| 1 | Application error | Uncaught exception, failed startup |
| 125 | Docker could not run the container | Bad flag, missing image, unreachable log driver |
| 126 / 127 | Command not executable / not found | A directory, wrong architecture / a typo in CMD |
| 137 (128 + 9) | SIGKILL | OOM killer, docker kill, stop timeout |
| 143 (128 + 15) | SIGTERM | docker stop behind --init |
docker stop sends SIGTERM and sends SIGKILL ten seconds later. The kernel ignores signals that a PID 1 has not installed a handler for, so a program that never handles SIGTERM sits out the grace period and dies with 137. BookNest's API handles it (Exec vs Shell Form); for programs that do not, docker run --init puts tini 11,240 in front. A restart policy hides a crash: the container runs again, but RestartCount has grown and docker logs still holds the crashed run's lines, so read them before you recreate the container.