Skip to content
compiler.dev

Process Completed With Exit Code 137: Fixes

Last updated

Process completed with exit code 137 means a process in your job was killed with SIGKILL, and on GitHub Actions the usual reason is that the runner ran out of memory. The number is 128 plus 9, where 9 is the SIGKILL signal. Below: how to confirm it is memory, how much RAM runners have, and fixes for Node, Jest, Gradle and Docker.

The exact message

Error: Process completed with exit code 137.

A shell step shows this when its command, or something it launched, died from SIGKILL. In Docker output you may also see Killed or OOMKilled: true. Other causes of 137 exist (a kill -9, a container stop timeout, a cancelled job), but out of memory is by far the most common in CI.

How much memory does a runner have?

Per the GitHub runner reference, checked October 2026:

RepositoryStandard Linux runnerRAM
Public4 CPU16 GB
Private2 CPU8 GB

Many builds that pass on a 16 or 32 GB laptop fail on a private-repository runner with 8 GB, especially when a tool starts one worker per detected CPU core.

Confirm it is out of memory

- name: Memory check after failure
  if: failure()
  run: |
    free -m
    sudo dmesg | grep -i -E "killed process|out of memory" | tail

If dmesg shows Out of memory: Killed process, you have your answer. Also log memory every few seconds during the build:

- run: |
    (while true; do date +%T; free -m | sed -n 2p; sleep 5; done) &

Causes and fixes

1. Node.js builds and bundlers

Node's default heap limit depends on the version and system memory, and large bundles can hit it. Raise the limit but keep it under the runner's RAM:

- run: npm run build
  env:
    NODE_OPTIONS: --max-old-space-size=6144

Also cut memory by turning off source maps in CI, or by running the type check and the build as separate steps.

2. Jest, Vitest or other test runners with too many workers

Each worker is a full process holding its own test environment, and leaky tests make it grow.

- run: npx jest --maxWorkers=2 --logHeapUsage
- run: npx jest --runInBand   # slowest, lowest memory

Find leaks with --detectOpenHandles and --logHeapUsage. Jest 29 and later also support --workerIdleMemoryLimit=1GB, which restarts workers that grow too large. Test sharding spreads tests across jobs, which also splits memory use.

3. Gradle and Maven

The Gradle daemon, the Kotlin compile daemon and the test JVMs each take their own heap, and together they can exceed 8 GB.

- run: ./gradlew build --no-daemon
  env:
    GRADLE_OPTS: -Xmx2g

In gradle.properties:

org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m
org.gradle.workers.max=2
kotlin.daemon.jvm.options=-Xmx1g

For Maven use MAVEN_OPTS: -Xmx2g and -T 1 instead of a large thread count. If tests fork JVMs, set forkCount and argLine with -Xmx in Surefire.

4. Docker builds and service containers

Either a container hit its memory limit or the host did. Compile steps inside docker build (Rust or C++ with high parallelism, for example) are typical. Lower parallelism (cargo build -j2, make -j2) and set explicit limits on memory-hungry services:

services:
  es:
    image: elasticsearch:8.15.0
    env:
      ES_JAVA_OPTS: -Xms512m -Xmx512m

5. A memory leak in your own code or tests

If memory rises with each test file, the cause is code. Fix the leak, or restart workers more often.

6. A cancelled or timed out job

Cancelling a run, or a step hitting [timeout-minutes](/errors/timeout-minutes), also kills processes. Rule out concurrency cancellation first (see The operation was canceled).

When tuning is not enough

Use a machine with more RAM. Options are a GitHub larger runner (see the larger runners docs) or a runner provider. compiler.dev's default Linux machine is 8 vCPU / 16 GB, a fresh VM per job, at $0.012 per minute as of October 2026, and you switch with runs-on: [self-hosted, Linux, compiler-ci]. See pricing and the runner size picker. If the job also runs out of disk, see No space left on device. A full runner crash looks different, see lost communication.

How to prevent it

  1. Record peak memory in CI and set an alert threshold below the runner's RAM.
  2. Pass explicit heap and worker limits to every tool instead of relying on auto-detection.
  3. Run linting, type checks, builds and tests as separate jobs.
  4. Run one heavy process at a time on small runners.
  5. Review dependency upgrades that increase bundle size or test memory.

FAQ

What does exit code 137 mean?

The process received SIGKILL. 137 equals 128 + 9. In CI it is almost always the kernel's out-of-memory killer.

Is exit code 137 the same as 143?

No. 143 is SIGTERM (128 + 15), a polite stop request often sent on cancellation. 137 is a forced kill.

Why does it work locally?

Your laptop has more RAM and a different core count. Runners have fixed, smaller memory.

Will adding swap help?

It can delay the kill but slows the build sharply. Reduce memory use or use a bigger machine instead.