Home › Kubernetes

OOMKilled (exit code 137) — how to fix

Last State:     Terminated
  Reason:       OOMKilled
  Exit Code:    137

Quick fix: Confirm with kubectl describe pod <pod> (Reason: OOMKilled). Check real usage with kubectl top pod <pod> --containers. Raise resources.limits.memory (and requests) in the Deployment, e.g. kubectl set resources deployment/myapp --limits=memory=1Gi --requests=memory=512Mi, and cap runtime heaps (JVM -XX:MaxRAMPercentage=75, Node --max-old-space-size).

What it means

Every container with resources.limits.memory runs in a cgroup with that hard cap. When the processes in it try to use more, the Linux OOM killer sends SIGKILL. Exit code 137 = 128 + 9 (SIGKILL). The pod then restarts and, if it keeps happening, goes into CrashLoopBackOff.

Confirm it:

kubectl describe pod mypod | grep -A5 "Last State"
kubectl get pod mypod -o jsonpath='{.status.containerStatuses[*].lastState.terminated.reason}'

A pod evicted due to node memory pressure shows Reason: Evicted instead — that's a node-level problem, not your container limit.

Fix 1: measure actual usage

kubectl top pod mypod --containers      # needs metrics-server

Compare with the configured limit:

kubectl get pod mypod -o jsonpath='{.spec.containers[*].resources}'

If usage under normal load sits close to the limit, the limit is simply too low.

Fix 2: raise the memory limit

In the Deployment manifest:

spec:
  template:
    spec:
      containers:
        - name: app
          resources:
            requests:
              memory: "512Mi"
            limits:
              memory: "1Gi"

Or imperatively:

kubectl set resources deployment/myapp -c app --requests=memory=512Mi --limits=memory=1Gi

Use Mi/Gi (binary units). 1G and 1Gi are different, and a lowercase m means milli — memory: 512m is half a byte, a classic mistake.

Also check for a LimitRange in the namespace that applies a small default limit when you don't set one:

kubectl get limitrange -n mynamespace -o yaml

Fix 3: make the runtime respect the limit

Many runtimes size their heap from total memory and can exceed the cgroup limit.

JVM (Java 10+ / 8u191+ are container-aware). Size the heap as a fraction of the limit and leave room for metaspace, threads and native memory:

env:
  - name: JAVA_TOOL_OPTIONS
    value: "-XX:MaxRAMPercentage=75.0"

Node.js — the V8 heap limit is set independently:

command: ["node", "--max-old-space-size=768", "server.js"]   # MiB, below a 1Gi limit

Python / Go — no heap flag to tune for Python; for Go 1.19+ set a soft limit: GOMEMLIMIT=900MiB.

Fix 4: find leaks or spikes

If memory grows steadily until the kill, it's a leak; if it jumps, it's a large request, batch, or file loaded into memory. Options:

Fix 5: init containers and sidecars

The reason may be on another container in the pod. kubectl describe pod lists each container's state; check init containers and sidecars (e.g. a log shipper) too, each with its own limit.

Last updated 2026-10-30.