Docker Container Exit Code 137: What It Means, How to Fix It
Exit code 137 is not a crash in your application code, it is the kernel or Docker forcibly killing the container, and the cause is almost always memory.
Docker container exit code 137 means the container received SIGKILL, signal 9, and 137 is simply 128 plus that signal number. Unlike most application crashes, this is not your code failing on its own, something outside the container, usually the Linux kernel's out-of-memory killer, or Docker's own memory limit enforcement, terminated it forcibly with no chance for the process to clean up or log why.
Confirm it is actually an OOM kill
Do not assume, check directly. docker inspect records exactly why the container stopped.
docker inspect CONTAINER_ID --format='{{.State.OOMKilled}} exit={{.State.ExitCode}}'
A result of true exit=137 confirms it definitively. If it comes back false with the same exit code, something else sent SIGKILL, a manual docker kill, an orchestrator health check giving up on the container, or a host-level process manager, and the investigation goes in a different direction.
Cross-check against the kernel's own log, which records OOM kill events independent of Docker.
dmesg -T | grep -i 'killed process'
journalctl -k | grep -i 'out of memory'
A matching timestamp and process name here is the second confirmation. If docker inspect says OOMKilled but dmesg shows nothing, the container likely hit its own cgroup memory limit rather than exhausting the host's memory entirely, both produce the same exit code but point at slightly different fixes.
Find out how much memory it actually needed
Before raising a limit blindly, find out what the container's real peak usage looked like leading up to the kill.
docker inspect CONTAINER_ID --format='{{.HostConfig.Memory}}'
A result of 0 means no explicit limit was set for this container specifically, meaning it was competing for whatever memory the host had free at the time, and got killed once the host itself ran low. A non-zero value in bytes is the configured cgroup limit that was actually exceeded.
docker stats CONTAINER_ID --no-stream
Run this repeatedly (or under watch) while the workload that triggers the issue runs, to see whether memory climbs steadily (a leak) or spikes suddenly at a specific operation (a batch job, a large file processed in memory, a burst of concurrent requests).
| Pattern observed | Likely cause |
|---|---|
| Memory climbs steadily over hours before the kill | A memory leak in the application, restarting only delays the next kill |
| Memory spikes suddenly right before the kill | A specific operation (large upload, batch job, unbounded query result) using memory faster than the limit allows |
| Multiple containers on the same host get killed around the same time | Host-level memory exhaustion, not any single container's fault specifically |
Fix the actual cause, not just the symptom
Raising the memory limit is sometimes the right answer and sometimes just delays the same failure. Decide based on what the pattern above showed.
- If memory climbs steadily without ever plateauing, that is a leak. Increasing the limit buys time before the next kill, it does not fix the underlying issue in the application.
- If usage spikes predictably during a specific operation and otherwise sits well within limits, raising the memory limit to comfortably cover that peak is a reasonable, direct fix.
- If multiple unrelated containers are getting killed around the same time, the host itself is oversubscribed, the fix is either more host memory or setting limits on every container so they cannot collectively exceed what the host actually has.
docker update --memory=512m --memory-swap=512m CONTAINER_ID
Distinguishing a real leak from an underprovisioned limit, on one container, once, is a focused investigation. Doing it across every container on a host, every time one gets killed, and remembering to check dmesg alongside docker inspect every time, is where this becomes routine toil. BashPilot checks OOMKilled status, correlates it against the kernel log and historical memory usage automatically, and tells you whether the pattern looks like a leak or a genuine capacity issue before you touch a limit.
Diagnosing a repeating OOM kill
Confirmed OOMKilled on the last 4 restarts. Memory usage climbed steadily over roughly 6 hours each time before hitting the 256MB limit, then reset to baseline immediately after restart. This pattern matches a memory leak, not a workload spike.
| Restart | Time to OOM | Memory at kill |
|---|---|---|
| 1 | 6.2h | 256MB |
| 2 | 5.8h | 256MB |
| 3 | 6.5h | 256MB |
Raising the limit buys roughly 12 hours before the same pattern likely recurs based on the growth rate observed. Applying the change now.
docker update --memory=512m --memory-swap=512m api_container
Try this on one of your own servers.
Start free trialVerify the fix actually holds
A container that stops restarting for an hour is not proof the issue is resolved, especially if the underlying pattern was a slow leak.
docker stats CONTAINER_ID --no-stream >> /tmp/memlog.txt; sleep 3600; docker stats CONTAINER_ID --no-stream >> /tmp/memlog.txt
Compare readings across several hours, not just before and immediately after the change. If memory usage is still climbing at the same rate under the new, higher limit, you have delayed the kill, not fixed the leak, and the application itself needs attention.
Prevent the repeat
- Set explicit memory limits on every container, not just the ones that have already caused a problem, so a future leak fails predictably instead of competing for whatever the host has free.
- Alert on memory usage trending toward a container's limit well before it actually gets killed, rather than finding out from a restart.
- For applications known to leak slowly, a scheduled restart during a low-traffic window is a legitimate short-term mitigation while the actual leak gets fixed, it is not a substitute for fixing it.