Docker exit code 137: what OOM-killed containers are telling you
⏱️ 2 min read
137 = 128 + SIGKILL
When a container stops with exit code 137, the kernel sent it SIGKILL (signal 9). Nine times out of ten, the Linux OOM killer did it: the container exceeded its memory cgroup limit and the kernel reclaimed the memory the hard way. The remaining cases are Docker Desktop restarting, or a platform supervisor enforcing a limit you did not know existed.
Confirm it in 60 seconds
docker inspect <container> --format '{{.State.OOMKilled}}'
docker inspect <container> --format '{{json .HostConfig.Memory}}'If OOMKilled: true, it is the cgroup limit. If Memory: 0, there is no limit on the container itself, so the kernel killed it because the host ran out of RAM, which is worse news.
The three usual suspects
- Limit set below the JVM or runtime's real appetite. A JVM inside a container with
-m 512mwill get killed: it commits heap beyond the cgroup before GC notices. Set explicit runtime limits (for Java 17+, rely on container-aware defaults or use-XX:MaxRAMPercentage=70). - Memory leaks that eventually cross any limit. Steady RSS growth across restarts means a leak. Capture
docker statsover time or profile before raising anything. - misplaced
--memory-swapsettings. IfMemorySwap == Memory, the container cannot swap, so a spike that would have been absorbed becomes a kill. Give headroom or accept the kill, but know which you chose.
What to actually do
Set the limit above the container's peak working set, not its average. Watch container_memory_max_usage_bytes in your metrics, and alert at 80% of the limit. And if your workload genuinely needs more memory than your node can give, a cheap hourly cloud box is the fastest lab: spin one up on DigitalOcean, reproduce the kill with a real memory profile, and size it properly before you redeploy. (Partner link — it never costs you extra.)
Exit 137 is not a bug, it is the kernel keeping a promise. Find which promise you broke.