Exit Code 137 Is Not Enough to Diagnose Linux OOM

When a command ends with Killed or a container reports 137, first establish its relation to SIGKILL. Memory pressure is one possible cause, but an operator signal, supervisor deadline or container stop handling can produce the same signal.

The same signal occurred without memory exhaustion

An owned Python child did nothing except wait, then received SIGKILL. Python reported returncode -9; the usual shell convention is 128+9=137. This experiment did not induce OOM. The observation therefore demonstrates why 137 alone cannot justify a memory increase.

Collect evidence for the same time and cgroup

journalctl -k --since "2026-09-21 00:00:00" --no-pager
systemctl show example.service -p Result -p ExecMainCode -p ExecMainStatus -p ControlGroup -p MemoryMax

Replace the timestamp and example.service with the actual incident. Correlate the process and time in kernel OOM records; on cgroup v2 inspect that service’s memory.events and memory.events.local. Because oom_kill is cumulative, a change across the incident is more useful than one current value. Check hierarchical accounting in the cgroup v2 documentation.

If permissions prevent journal access or logs rotated away, record missing evidence rather than “no OOM.” A service can hit its cgroup limit while the host still has available memory. Conversely, if a stop timeout aligns with SIGKILL and there is no corroborating OOM evidence, investigate shutdown handling.

Based on the confirmed cause, adjust concurrency, batch size, a memory limit or a shutdown grace period one at a time, then observe recurrence and memory use for the same workload. Verification does not require deliberately exhausting a production server.