Platforms 6 min read

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.

By BashPilot Team
BashPilot AI server management One request plans, executes and verifies the fix, on every server. See pricing

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.

check the OOMKilled field directly
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.

check the kernel log for OOM killer activity
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.

check the container's configured limit
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.

monitor live memory usage to catch the pattern
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 observedLikely cause
Memory climbs steadily over hours before the killA memory leak in the application, restarting only delays the next kill
Memory spikes suddenly right before the killA 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 timeHost-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.
set or raise a container's memory limit
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.

In BashPilot

Diagnosing a repeating OOM kill

app.bashpilot.com
the api container keeps restarting, exit code 137, why
BashPilot

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.

RestartTime to OOMMemory at kill
16.2h256MB
25.8h256MB
36.5h256MB
raise the limit to 512MB for now and flag this for the dev team
BashPilot

Raising the limit buys roughly 12 hours before the same pattern likely recurs based on the growth rate observed. Applying the change now.

bash
docker update --memory=512m --memory-swap=512m api_container
Example output, not a screenshot of a specific customer's server.

Try this on one of your own servers.

Start free trial

Verify 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.

watch memory trend over a longer window
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.
Share LinkedIn X
Questions

Frequently asked questions

What does Docker exit code 137 mean?

137 is 128 plus signal number 9, meaning the container received SIGKILL. It almost always indicates the container was forcibly terminated, most commonly by the Linux kernel's out-of-memory killer or by Docker enforcing a configured memory limit, rather than the application exiting or crashing on its own.

How do I confirm a Docker container was killed for using too much memory?

Run `docker inspect CONTAINER_ID --format='{{.State.OOMKilled}}'`. A result of `true` confirms it directly. You can cross-check with `dmesg -T | grep -i 'killed process'` to see the kernel's own record of the event, which also names the process and the memory conditions at the time.

Does a Docker container need an explicit memory limit to get OOM killed?

No. A container with no memory limit set (`docker inspect` shows `HostConfig.Memory` as 0) can still be killed if the host itself runs out of available memory, since it is competing unrestricted for whatever the host has free at any given moment.

Should I just increase the memory limit when a container gets exit code 137?

Only after checking whether the memory usage pattern is a steady leak or a legitimate spike during specific operations. Raising the limit fixes a genuine capacity shortfall but only delays the next kill if the real cause is a leak that will eventually exceed any limit given enough time.

Why does docker-compose restart a container automatically after exit code 137?

This is normal behavior when a `restart` policy such as `always` or `unless-stopped` is set, which restarts the container regardless of why it stopped, including an OOM kill. The restart policy does not distinguish between a graceful exit and a forced kill, so a repeatedly OOM-killed container will keep restarting indefinitely until the underlying memory issue is fixed.

Put your servers on autopilot.

Connect a server in about a minute. The first week is on us.