Photo by Wolfgang Weiser on Unsplash
So I was running a Node.js app in a Docker container on a DigitalOcean droplet at like 11pm, and it just... died. No warning, no helpful message. Just exit code 137 staring back at me from the logs. I honestly thought I'd broken something in the Dockerfile. Spent a good 45 minutes chasing the wrong rabbit before I figured out what was actually going on.
If you're hitting Docker error 137 right now, here's the short version: your container didn't crash. It was murdered — specifically by the Linux kernel's OOM (Out of Memory) killer. And once you know that, fixing it becomes a lot more straightforward.
What Docker Error 137 Actually Looks Like
You'll usually see it when you run docker ps -a or check container logs:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS
a3f9b2c1d4e5 myapp "node app" 2 hours ago Exited (137) 5 minutes ago
$ docker inspect a3f9b2c1d4e5 --format='{{.State.OOMKilled}}'
true
That last command is the one I wish someone had shown me years ago. OOMKilled: true is your smoking gun. Exit code 137 is just 128 + 9 — where 9 is the SIGKILL signal. The OS sends SIGKILL, Docker catches it, and reports 137. Simple math, brutal outcome.
Why This Happens
The Linux kernel has an OOM killer process that wakes up when available memory gets critically low. It looks around, picks the most "expensive" process it can find, and kills it. Docker containers are prime targets because they can look like memory hogs from the kernel's perspective.
There are a few common scenarios I've seen cause this repeatedly:
You set a memory limit that's too low. Maybe you set --memory=256m thinking that'd be fine, but your app needs 400MB under load. Docker enforces that limit hard, and when the container exceeds it, the OOM killer steps in.
Your host machine is just out of memory. No memory limit on the container, but the host box itself is running low. The kernel panics and starts killing processes — your container's just the unlucky one.
Memory leak in the app. Honestly, this one is embarrassing when it's your own code. The container runs fine for a few hours, slowly eats more and more RAM, and then boom — 137. I've seen this with Node.js apps that weren't cleaning up event listeners properly.
Fix 1: Increase (or Remove) the Memory Limit
First, check what limits are currently set on your container:
docker inspect | grep -i memory
If you're running with a compose file, bump up the memory limit:
# docker-compose.yml
services:
myapp:
image: myapp:latest
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
Or if you're running a container directly:
docker run --memory="512m" --memory-swap="1g" myapp:latest
The --memory-swap flag is worth setting explicitly. If you don't set it, Docker defaults to 2x your memory limit as swap. Setting it to a specific value gives you more control — or set it equal to --memory to disable swap entirely for that container.
Fix 2: Check What's Actually Eating Memory
Before you just throw more RAM at the problem, it's worth actually profiling what's going on. Docker has a built-in stats command that's surprisingly useful:
docker stats --no-stream
This gives you a snapshot of CPU, memory usage, and network I/O across all running containers. If you see one container sitting at 95%+ memory usage constantly, that's your culprit.
For a deeper look, exec into the container while it's still alive and check the process table:
docker exec -it /bin/sh
# inside the container:
top
# or if you have it:
ps aux --sort=-%mem | head -10
I once found a rogue ffmpeg process spawned by a media conversion job that wasn't getting cleaned up properly. It was sitting there eating memory for hours. Never would've caught it without actually looking inside the container.
Fix 3: Check Host-Level Memory and Tune Swappiness
If you're not limiting container memory but still getting 137 errors, the host machine itself might be the problem. SSH in and check:
free -h
vmstat -s | grep "used memory"
dmesg | grep -i "oom\|killed"
That dmesg command is gold. It'll show you the kernel's OOM kill log with timestamps, so you can see exactly when and why things got killed.
If your host is consistently running low on memory, you might also want to check the swappiness setting. A value of 60 (the default) means the kernel is pretty aggressive about swapping. You can dial it back:
# Check current value
cat /proc/sys/vm/swappiness
# Lower it temporarily (resets on reboot)
sudo sysctl vm.swappiness=10
# Make it permanent
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
Lowering swappiness means the kernel will try harder to keep things in RAM before hitting swap — which can help with performance but obviously doesn't solve an actual memory shortage.
Fallback: Set a Restart Policy With a Backoff
Look, sometimes you can't immediately fix the root cause — maybe it's a vendor image you don't control, or you're waiting on a deploy window. In that case, at least set a restart policy so Docker tries to recover automatically:
docker run --restart=on-failure:5 --memory="512m" myapp:latest
The on-failure:5 tells Docker to restart the container up to 5 times if it exits with a non-zero code (which 137 definitely is). It's not a fix, but it buys you time. Combine it with proper monitoring — something like docker events piped to a log or an alerting tool — so you actually know when it's happening.
One more thing: if you're on Kubernetes instead of plain Docker, exit code 137 works the same way but you'd look at the pod's lastState in kubectl describe pod and check for OOMKilled: true there. Same root cause, different tooling.
Hope this saves you the hour and a half I lost staring at logs. The docker inspect + OOMKilled check should always be your first stop when you see 137 — it cuts through the noise fast.
๋๊ธ
๋๊ธ ์ฐ๊ธฐ