Exit Code 137 (tested)
Exit code 137 never comes from your program choosing to exit with that number — it is not a valid argument to exit(). It means something sent the process SIGKILL (signal 9), and the shell or container runtime reported it back as 128 + 9. We verified this directly: sending real signals and reading the real exit codes, in bash and in Docker.
1. The formula: 128 + signal number
When a process is killed by a signal rather than calling exit() itself, Unix shells and container runtimes report the exit status as 128 + signal number. We measured this directly on this box:
$ bash -c 'sleep 30 & PID=$!; kill -9 $PID; wait $PID; echo "exit: $?"'
Killed
exit: 137
$ bash -c 'sleep 30 & PID=$!; kill -15 $PID; wait $PID; echo "exit: $?"'
exit: 143
kill -9 is SIGKILL (9), so 128 + 9 = 137. kill -15 is SIGTERM (15), giving 143. The common ones you'll meet:
| Exit code | Signal | Meaning |
|---|---|---|
| 137 | SIGKILL (9) | Forcibly killed — cannot be caught or ignored by the process. Usually the OS/container runtime running out of patience or memory. |
| 143 | SIGTERM (15) | Asked to terminate gracefully. Docker's default docker stop sends this first, then SIGKILL after a grace period. |
| 139 | SIGSEGV (11) | Segmentation fault — the process accessed memory it shouldn't have. |
| 134 | SIGABRT (6) | The process called abort(), often from a failed assertion. |
A process can never choose to exit with 137 itself — exit(137) in your own code is indistinguishable from a real SIGKILL in the shell, which is a common source of confusion when debugging. If you see it and you're sure nothing killed the process, check your own exit code logic first.
2. Docker: 137 means something killed the container, but not always OOM
We ran two real containers to compare. First, a container we killed manually with no memory pressure at all:
$ docker run -d --name test sleep 60
$ docker kill -s SIGKILL test
$ docker inspect test --format '{{.State.ExitCode}} oom={{.State.OOMKilled}}'
137 oom=false
Then a container we deliberately starved of memory with Docker's own --memory limit, doing nothing but allocating RAM in a loop:
$ docker run --name test --memory=10m alpine sh -c "a='A'; while true; do a=\$a\$a\$a\$a; done"
$ docker inspect test --format '{{.State.ExitCode}} oom={{.State.OOMKilled}}'
137 oom=true
Both report exit code 137 — Docker (and Kubernetes, which uses the same underlying mechanism) only distinguishes them through a separate field. In plain Docker it's docker inspect's .State.OOMKilled; in Kubernetes it's the pod's reason: OOMKilled next to exitCode: 137 in kubectl describe pod. If you only look at the exit code, a genuine memory limit and someone running docker kill look identical.
3. How to tell which one happened to you
- Docker Compose / plain Docker:
docker inspect <container> --format '{{.State.OOMKilled}}'—truemeans the container's own memory limit (or the host's, if unset) was hit. - Kubernetes:
kubectl describe pod <name>and look forLast State: Terminated, Reason: OOMKillednext toExit Code: 137. If the reason saysErrorinstead, it was a different kill. - AWS ECS: a task that exits 137 from a memory limit shows
OutOfMemoryErroras the stopped reason in the task's stopped-reason field, not just the exit code. - Bare process / systemd: check
journalctl -u <service>or (if you have permission)dmesgfor a kernel line likeOut of memory: Killed process <pid>— see our out-of-memory-killed guide for exactly how we reproduced and read one of these. - Nobody killed it on purpose and there's no memory pressure: check whether your own orchestrator, health-check, or a teammate's script is sending the kill — 137 is never spontaneous.
4. Fixing an OOM-caused 137
Once you've confirmed it's a real memory limit (not a manual kill), the fix is one of:
- Raise the container/pod memory limit if the workload genuinely needs more (check actual peak usage first with
docker statsor your orchestrator's metrics, don't just guess upward). - Fix a memory leak if usage climbs without bound over time rather than plateauing — a limit increase just delays the same crash.
- For language-specific heap limits hit well below the container's memory ceiling (e.g. Node's V8 heap), the fix is different — see our guide on that specific failure mode rather than raising the container limit, which won't help.
5. Fixing a non-OOM 137 (someone/something killed it on purpose)
If OOMKilled is false, look for: a deploy script or CI job calling docker kill/kill -9 directly instead of a graceful stop, a Kubernetes liveness probe failing and triggering a forced restart, or a process manager (systemd, supervisord, PM2) configured with too short a shutdown grace period so it escalates straight to SIGKILL before your app can finish handling SIGTERM.
Frequently asked questions
Can my own code cause exit code 137?
No. Exit code 137 only ever means a process was killed by SIGKILL (signal 9); a program cannot produce it by calling exit() itself. If you see 137 and nothing obviously killed the process, check that something else isn't sending the signal (orchestrator, health check, CI step) before assuming it's a bug in your code.
Does exit code 137 always mean out of memory?
No, we confirmed this directly: a container we killed manually with plenty of free memory also reported exit code 137. Docker and Kubernetes only distinguish the two through a separate field (OOMKilled in Docker, the pod's termination reason in Kubernetes), not the exit code itself.
What's the difference between 137 and 143?
Both are kill signals reported as 128 + signal number: 137 is SIGKILL (9, immediate, cannot be caught), 143 is SIGTERM (15, a polite request to shut down that a process can catch and handle). Docker's docker stop sends SIGTERM first and escalates to SIGKILL only if the process hasn't exited after the grace period.
How do I check if a Kubernetes pod's 137 was an OOM kill?
Run kubectl describe pod <name> and look at the Last State section: Reason: OOMKilled next to Exit Code: 137 confirms a memory-limit kill. If Reason says Error or something else instead, a different mechanism killed it.
I raised the memory limit and it still exits 137 eventually — why?
That usually means a real memory leak rather than an undersized limit: usage climbs without bound instead of plateauing, so any fixed limit just delays the same crash. Watch the container's memory usage over time (docker stats or your orchestrator's metrics) to tell a leak (steadily climbing) from a one-off spike (fixed limit too low).
Written with AI assistance. Measured on 2026-10-02 on Debian 13 / Linux 6.12, bash 5.x, Docker 29.8.1. We sent real SIGKILL/SIGTERM signals to processes and read bash's own $? exit codes, and ran real Docker containers (one manually killed, one actually OOM-killed via --memory) to compare the ExitCode and OOMKilled fields in `docker inspect`. PlainHeaders is our extension; bash and Docker are free.