Docker build: failed to solve process "/bin/sh -c ..."
Diagnose Docker build "failed to solve" errors caused by a failing RUN command, missing files, or a base image that changed.
Symptoms
- ERROR: failed to solve: process "/bin/sh -c apt-get update" did not complete successfully: exit code 100
- The build worked yesterday and now fails at the same step
- The error names a RUN command with a non-zero exit code
Possible causes
- A RUN command fails because a package or URL is unavailable
- A COPY references a file excluded by .dockerignore or missing locally
- The base image tag moved to a newer version with different tooling
- The build cache is stale, masking a change
Diagnosis steps
Read the exit code and the failing command
Interpretation
The exit code maps to the tool; 100 from apt usually means a repository error.
Run the same command in an interactive container
docker run --rm -it <base-image> shInterpretation
Reproducing interactively shows the actual tool output the build log truncated.
Rebuild with cache disabled
docker build --no-cache .Interpretation
If it passes without cache, a poisoned cache layer was the cause.
Root cause
The BuildKit solver reports "failed to solve" when a build step exits non-zero. The named RUN command is what failed, but the reason is often hidden: an unavailable mirror, a missing local file for COPY, or a base image whose tag now points at a different version. The solver reports the step, not the underlying tool error.
Fix
Reproduce the failing command interactively to see its real output, and pin base image versions by digest so the environment does not shift silently. Fix mirrors and network access for package installs, ensure COPY sources exist and are not excluded by .dockerignore, and rebuild with --no-cache when a stale layer is suspected.
Verify the fix
Rebuild the image; the solver completes all steps and the image builds, with the previously failing RUN command finishing at exit code 0.
Symptoms
ERROR: failed to solve: process "/bin/sh -c ..." did not complete successfully: exit code N. It may begin suddenly if a base image tag was updated upstream.
Diagnosis
Extract the failing command and run it interactively:
docker run --rm -it ubuntu:22.04 sh
# then paste the failing command to see its output
apt-get update
Rebuild with --no-cache to rule out a stale layer.
Fix
Pin base images and fix the step:
FROM ubuntu:22.04@sha256:<digest>
RUN apt-get update && apt-get install -y --no-install-recommends curl
Ensure COPY sources are present and not in .dockerignore.
Verification
Rebuild the image; all steps complete and the previously failing command exits 0, producing the intended image.
Pinning the Build Environment
Most “failed to solve” surprises come from the environment moving rather than the Dockerfile changing. A base image tag like node:20 is mutable, so a rebuild can pick up a newer patch that drops a package or changes a default shell. Pinning by digest makes the build reproducible and turns an upstream update into an explicit, reviewable change. Similarly, package installs that reach the network fail whenever a mirror is down; installing prerequisites from a pinned snapshot or a vendored artifact keeps builds independent of external availability and explains failures that appear only in one CI region.