Error Medic

CircleCI Build Failed: How to Fix OOM, Permission Denied, and Timeout Errors

CircleCI build failed? Diagnose and fix out-of-memory, permission denied, and timeout errors with step-by-step commands and config fixes. Resolve in minutes.

Last updated:
Last verified:
2,150 words
Key Takeaways
  • CircleCI builds fail for four primary reasons: insufficient executor memory (OOM kill), filesystem or registry permission errors, step-level or job-level timeouts, and misconfigured environment variables or orb versions.
  • Out-of-memory failures surface as 'Killed' or exit code 137 in logs; permission errors appear as 'EACCES', 'permission denied', or 'exit status 126'; timeouts show 'Exceeded 10 hours (with no output)' or 'CircleCI received exit code 124'.
  • Quick triage: check the failing step's raw log for the exact exit code, then cross-reference with the resource_class, working_directory, and environment block in your .circleci/config.yml before reaching for SSH debugging.
Fix Approaches Compared
MethodWhen to UseTime to ApplyRisk
Upgrade resource_classExit code 137 / OOM kill / heap exhaustion5 min (config change)Low — minor cost increase
SSH debug sessionIntermittent failures, undocumented permission errors15–30 minLow — read-only by default
Restore cache with a new keyCorrupt node_modules or pip cache causing permission errors10 minLow — forces clean install
Increase no_output_timeoutLong compile or test steps that time out silently2 min (config change)Low — extends billing
Rerun with --debug or verbose flagsOpaque failures with no clear error message5 minLow — log verbosity only
Rerun failed jobs from the startFlaky network-dependent steps (Docker pull, npm install)1 min (UI click)None
Downgrade or pin orb versionOrb update introduced breaking changes10 minMedium — may miss security patches

Understanding Why CircleCI Builds Fail

CircleCI executes your pipeline inside an ephemeral executor — a Docker container, Linux VM, macOS VM, or Windows VM — that is created fresh for every job. Because the environment is isolated and stateless, failures that "never happen locally" are almost always caused by one of four environmental mismatches: resource limits, filesystem permissions, wall-clock timeouts, or missing credentials.

Understanding the exit code in the failing step is the fastest path to the correct fix.

Exit Code Signal Most Likely Cause
1 General error Script logic, non-zero test result
124 SIGALRM timeout command or CircleCI step timeout
126 Permission error Binary not executable
127 Not found Missing dependency or PATH issue
137 SIGKILL (OOM) Executor ran out of memory
139 SIGSEGV Segmentation fault in native code

Step 1: Read the Raw Log

Click the failing step name in the CircleCI UI to expand it. Scroll to the very bottom of that step — CircleCI truncates output in the middle but always preserves the final lines where the fatal error appears. Look for:

Killed
Exited with code exit status 137

or

permission denied: ./scripts/deploy.sh
Exited with code exit status 126

or

Too long with no output (exceeded 10m0s): context deadline exceeded

If the log is ambiguous, enable SSH access: open the job in the UI, click Rerun job with SSH, wait for it to start, then copy the SSH command shown and connect. From there you can ls -la, inspect /proc/meminfo, or re-run the failing command interactively.


Step 2: Fix Out-of-Memory (OOM) Failures — Exit Code 137

The Linux OOM killer sends SIGKILL (signal 9) to the process consuming the most memory, which is why you see Killed with no further explanation. Jest, webpack, Gradle, and the JVM are the most common culprits.

Fix A — Upgrade the resource_class:

jobs:
  build:
    docker:
      - image: cimg/node:20.11
    resource_class: medium+   # was: medium (2 vCPU / 4 GB)
    steps:
      - checkout
      - run: npm ci
      - run: npm test

Available Docker resource classes in ascending memory order: small (1 vCPU / 2 GB), medium (2/4 GB), medium+ (3/6 GB), large (4/8 GB), xlarge (8/16 GB), 2xlarge (16/32 GB).

Fix B — Limit Node.js heap size:

- run:
    name: Run Jest with bounded heap
    command: node --max-old-space-size=2048 node_modules/.bin/jest --runInBand
    environment:
      NODE_OPTIONS: "--max-old-space-size=2048"

The --runInBand flag forces Jest to run tests serially rather than forking worker processes, dramatically reducing peak memory.

Fix C — Limit JVM heap for Gradle/Maven:

- run:
    name: Build with bounded JVM
    command: ./gradlew build
    environment:
      JAVA_TOOL_OPTIONS: "-Xmx2g -Xms512m"

Step 3: Fix Permission Denied Errors — Exit Code 126 / EACCES

Permission errors in CircleCI fall into three sub-categories:

3a. Script not executable

If your repo contains shell scripts committed without the executable bit, CircleCI will fail with permission denied. Fix it locally and recommit:

git update-index --chmod=+x scripts/deploy.sh
git commit -m "fix: make deploy script executable"
git push

Alternatively, call bash explicitly inside your config so the executable bit is irrelevant:

- run: bash scripts/deploy.sh

3b. Docker socket or volume permission errors

When running Docker-in-Docker, the circleci user inside the executor may not have access to /var/run/docker.sock. Use the setup_remote_docker step and never mount the host socket directly:

steps:
  - setup_remote_docker:
      version: docker24
      docker_layer_caching: true
  - run: docker build -t myapp:$CIRCLE_SHA1 .

3c. npm / pip global install permission errors

Global installs attempt to write to /usr/local/lib, which requires root. Instead, configure a per-user prefix:

- run:
    name: Configure npm global prefix
    command: |
      mkdir -p ~/.npm-global
      npm config set prefix '~/.npm-global'
      echo 'export PATH=~/.npm-global/bin:$PATH' >> $BASH_ENV
- run: npm install -g your-tool

For pip, prefer pip install --user or use a virtualenv:

- run: pip install --user -r requirements.txt

Step 4: Fix Timeout Errors

CircleCI enforces two independent timeout mechanisms:

  1. No-output timeout (default: 10 minutes) — if a step produces no stdout/stderr for 10 minutes, CircleCI kills it.
  2. Job-level timeout — free tier jobs are killed after 30 minutes; paid tiers allow up to 5 hours by default.

Fix A — Increase no_output_timeout for long steps:

- run:
    name: Run integration tests
    command: pytest tests/integration/ -v
    no_output_timeout: 30m

Fix B — Force progress output for silent steps (e.g., large downloads):

- run:
    name: Download large artifact with progress
    command: curl -# -o artifact.tar.gz https://storage.example.com/artifact.tar.gz

The -# flag outputs a progress bar, which counts as output and resets the no-output timer.

Fix C — Increase job timeout at the workflow level:

workflows:
  build_and_deploy:
    jobs:
      - build:
          context: production
      - deploy:
          requires:
            - build

Note: per-job wall-clock timeouts require a CircleCI paid plan and are set in the CircleCI project settings UI under Advanced Settings > Maximum Job Runtime.


Step 5: Validate Your Config Before Pushing

Many build failures are caused by YAML syntax errors or invalid config keys that could be caught locally:

# Install the CircleCI CLI
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/main/install.sh | bash

# Validate config
circleci config validate .circleci/config.yml

# Pack and validate if using orbs or multiple files
circleci config pack .circleci/ | circleci config validate -

# Process config to see the expanded version
circleci config process .circleci/config.yml

Step 6: Isolate Flaky Failures with Rerun

If a build fails inconsistently (especially on Docker image pulls or npm install), use CircleCI's rerun capabilities:

  • Rerun from failed: restarts only the failed job, preserving workspace artifacts from earlier jobs.
  • Rerun with SSH: provides an interactive shell for manual investigation.
  • Rerun with no cache: forces a clean build, bypassing potentially corrupt caches.

To trigger a no-cache rerun via the API:

curl -X POST \
  --url "https://circleci.com/api/v2/pipeline" \
  --header "Circle-Token: $CIRCLECI_TOKEN" \
  --header "content-type: application/json" \
  --data '{"branch": "main", "parameters": {"run_without_cache": true}}'

Frequently Asked Questions

bash
#!/usr/bin/env bash
# CircleCI Build Failure Diagnostic Script
# Run these commands locally (requires circleci CLI) or in an SSH debug session

set -euo pipefail

echo "=== 1. Validate CircleCI config ==="
circleci config validate .circleci/config.yml && echo "Config is valid" || echo "Config has errors"

echo ""
echo "=== 2. Check executable bits on all scripts referenced in config ==="
grep -Eo '(bash|sh|run:.*\./[^ ]+)' .circleci/config.yml \
  | grep -Eo '\./[^ ]+' \
  | sort -u \
  | while read -r script; do
      if [ -f "$script" ]; then
        if [ ! -x "$script" ]; then
          echo "NOT EXECUTABLE: $script (fix: git update-index --chmod=+x $script)"
        else
          echo "OK: $script"
        fi
      fi
    done

echo ""
echo "=== 3. List resource_class settings in config ==="
grep -A1 'resource_class' .circleci/config.yml || echo "No explicit resource_class found (defaulting to medium)"

echo ""
echo "=== 4. Check for no_output_timeout settings ==="
grep -n 'no_output_timeout' .circleci/config.yml || echo "No custom timeouts found (default is 10m)"

echo ""
echo "=== 5. Detect potential OOM risk — Node.js heap config ==="
if grep -q 'jest\|webpack\|next build' .circleci/config.yml; then
  if ! grep -q 'max-old-space-size\|NODE_OPTIONS' .circleci/config.yml; then
    echo "WARNING: Node.js build steps found but no heap limit set. Add NODE_OPTIONS=--max-old-space-size=2048"
  else
    echo "OK: NODE_OPTIONS heap limit is configured"
  fi
fi

echo ""
echo "=== 6. Detect potential OOM risk — JVM config ==="
if grep -q 'gradlew\|mvn\|java' .circleci/config.yml; then
  if ! grep -q 'JAVA_TOOL_OPTIONS\|Xmx' .circleci/config.yml; then
    echo "WARNING: JVM steps found but no heap limit. Add JAVA_TOOL_OPTIONS=-Xmx2g"
  else
    echo "OK: JVM heap limit is configured"
  fi
fi

echo ""
echo "=== 7. Locally simulate the job (requires Docker) ==="
echo "Run this command to execute your build job locally:"
echo "  circleci local execute --job build"
echo ""
echo "=== 8. Process and expand full config (shows orb substitutions) ==="
circleci config process .circleci/config.yml > /tmp/circleci_expanded.yml
echo "Expanded config written to /tmp/circleci_expanded.yml"
wc -l /tmp/circleci_expanded.yml

echo ""
echo "=== Diagnostic complete ==="
E

Error Medic Editorial

Error Medic Editorial is a team of senior DevOps and SRE engineers who have collectively operated CI/CD pipelines across hundreds of production environments. We specialize in distilling complex infrastructure failure patterns into actionable, evidence-based troubleshooting guides. Our contributors have deep experience with CircleCI, GitHub Actions, Jenkins, and Kubernetes, and we verify every command in a live environment before publishing.

Sources

Related Articles in Circleci

Explore More DevOps Config Guides