Skip to content
Latchkey

Java Process Exit Code 137 (OOM-Killed) in CI - Heap vs Container Limit

Exit code 137 is 128 + 9 - the process received SIGKILL. For a JVM in CI that is the kernel/container OOM killer terminating it because total memory (heap + Metaspace + thread stacks + off-heap) exceeded the container or runner limit.

What this error means

A Java step dies with exit code 137 and often just Killed, with no Java stack trace - SIGKILL cannot be caught. It happens even when -Xmx seems modest, because non-heap memory also counts toward the container limit.

CI log
Killed
Error: Process completed with exit code 137.

Common causes

Total RSS exceeded the container/runner limit

The JVM’s real memory is heap PLUS Metaspace, thread stacks, code cache, and direct/off-heap buffers. A heap that fits can still push total RSS over the container cap and get OOM-killed.

Heap not aware of the container limit

On an old JVM, or with a fixed -Xmx larger than the container, the JVM grabs more than the cgroup allows and the kernel kills it.

How to fix it

Cap heap below the container limit

Leave headroom for non-heap memory. A common rule is heap <= ~75% of the container limit.

Terminal
# explicit cap
java -Xmx1500m -jar app.jar   # in a 2 GB container
# or let the JVM read the cgroup limit
java -XX:MaxRAMPercentage=75 -jar app.jar

Account for all memory regions

  1. Add headroom for Metaspace, thread stacks, and direct buffers beyond -Xmx.
  2. Reduce concurrent JVMs (test forks, Gradle workers) so they do not sum past the limit.
  3. Use a larger runner/container for genuinely memory-heavy builds.

How to prevent it

  • Size heap to a percentage of the container limit with -XX:MaxRAMPercentage.
  • Account for non-heap memory when sizing, not just -Xmx.
  • Right-size the runner for memory-heavy Java builds.

Frequently asked questions

Why no OutOfMemoryError, just "Killed"?
An OutOfMemoryError is thrown by the JVM when its own heap is exhausted. Exit 137 is the OS killing the whole process via SIGKILL because total memory exceeded the container limit - the JVM never gets to throw anything.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →