Docker Error Guide: 'did not complete successfully: exit code' — Fix RUN Build Failures
Fix Docker 'process did not complete successfully: exit code' in BuildKit: read the failing RUN step, reproduce it interactively, fix missing deps and network, and get builds passing again.
- #docker
- #troubleshooting
- #errors
- #build
Stuck on this Docker with AI error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
process "/bin/sh -c ..." did not complete successfully: exit code: N is BuildKit reporting that a RUN instruction in your Dockerfile exited non-zero. The build itself is working correctly — it faithfully ran your command, the command failed, and BuildKit stopped. The real problem is inside that RUN step: a failing package install, a missing file, a network error, a compilation failure, or a script that returned an error.
The literal error names the command and exit code:
------
> [builder 4/9] RUN npm ci && npm run build:
0.847 npm error code EUSAGE
0.849 npm error The `npm ci` command can only install with an existing package-lock.json.
------
Dockerfile:12
--------------------
12 | >>> RUN npm ci && npm run build
--------------------
ERROR: failed to solve: process "/bin/sh -c npm ci && npm run build" did not complete successfully: exit code: 1
Symptoms
- The build stops at a specific
[stage X/Y] RUN ...step withdid not complete successfully: exit code: N. - The lines just above the error (from BuildKit’s step output) contain the actual failure from the command.
- The step succeeds locally but fails in CI, or vice versa (environment or cache differences).
- Exit code hints at the class: 1 (general), 127 (command not found), 100 (apt), 137 (OOM-killed mid-step).
Common Root Causes
- A genuinely failing command — tests, linters, compilers, or
npm run buildreturning non-zero. - Missing files due to build context/.dockerignore — a lockfile or source path not copied before the step runs.
- Network failures in the step —
apt-get/pip/npmunable to reach a mirror, DNS failure, or an expired package index. - Missing base dependency — the command (
git,make,curl) is not installed in the image (exit code: 127). - Non-idempotent or order-dependent steps — a
RUNthat assumes state from a layer that changed or was cache-invalidated. - OOM during the step — a memory-hungry compile killed by the kernel, surfacing as exit 137.
Diagnostic Workflow
Read the lines immediately above the ERROR: failed to solve — that is the command’s own output and usually states the real cause. Then get the full build log with plain progress:
docker build --progress=plain -t app . 2>&1 | tail -40
Reproduce the failing step interactively by shelling into the last successful stage. Comment out the failing RUN, build, then run its command by hand:
docker build --target builder -t app-debug . # build up to the good stage
docker run --rm -it app-debug /bin/sh
# inside: run the failing command manually and watch the real error
npm ci && npm run build
Check whether required files actually made it into the context:
docker build --progress=plain . 2>&1 | grep -i 'COPY\|not found\|no such file'
cat .dockerignore
Rule out a caching/stale-layer effect:
docker build --no-cache -t app .
Check for an OOM kill if the exit code is 137:
dmesg -T | grep -i 'killed process\|out of memory'
Example Root Cause Analysis
A CI build failed at:
ERROR: failed to solve: process "/bin/sh -c npm ci && npm run build" did not complete successfully: exit code: 1
The lines above read npm ci ... can only install with an existing package-lock.json. The Dockerfile did COPY package.json ./ and then RUN npm ci — but package-lock.json was never copied because the COPY pattern only matched package.json, and npm ci strictly requires the lockfile.
The fix was to copy both manifests before installing: COPY package.json package-lock.json ./. This also improved caching, since the dependency layer now invalidates only when the lockfile changes. The team verified locally by building with --no-cache and confirmed the step passed, then re-ran CI green.
Prevention Best Practices
- Read the step output above the ERROR line first — the exit code alone is not the cause; the command’s own message is.
- Copy all required manifests before install steps (lockfiles included) and keep
.dockerignorefrom excluding build-time files. - Pin and cache dependencies so a package index change does not fail a step mid-pipeline.
- Make RUN steps idempotent and independent of state that caching might drop.
- Give builders enough memory so heavy compiles are not OOM-killed (exit 137); split or limit parallelism if needed.
- Build with
--progress=plainin CI so the full failing output is captured in logs.
Quick Command Reference
docker build --progress=plain -t app . 2>&1 | tail -40 # see the real failure
docker build --target <stage> -t dbg . && docker run --rm -it dbg sh
docker build --no-cache -t app . # rule out stale cache
cat .dockerignore # is a needed file excluded?
dmesg -T | grep -i 'out of memory' # exit 137 = OOM
Conclusion
did not complete successfully: exit code: N means BuildKit did its job and your RUN command did not. The fix is never in the message itself — it is in the step’s output just above it. Read that output, reproduce the step by shelling into the prior stage, and address the real cause: a missing lockfile, an uninstalled tool (127), a network failure, or an OOM (137). For a build that fails before reaching a step, see the failed to solve with frontend dockerfile.v0 guide and the full Docker guides.
Fixed it? Get 500 Docker with AI & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.