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 codeSignalMeaning
137SIGKILL (9)Forcibly killed — cannot be caught or ignored by the process. Usually the OS/container runtime running out of patience or memory.
143SIGTERM (15)Asked to terminate gracefully. Docker's default docker stop sends this first, then SIGKILL after a grace period.
139SIGSEGV (11)Segmentation fault — the process accessed memory it shouldn't have.
134SIGABRT (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

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:

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.