docker build failed (tested)

docker build failing is almost always one of three things: a COPY/ADD instruction pointing at a file that isn't in the build context, a RUN command that exits non-zero, or a FROM base image BuildKit can't fetch. We reproduced all three on a live box running Docker 29.8.1 with BuildKit, and recorded the exact error text each one prints, so you can match yours below. This is about docker build itself (building an image from a Dockerfile); if your failure happens on docker compose up instead, see Docker Compose Up Errors, which covers a different set of errors (bad service names, port conflicts, bad compose-file image tags).

1. Quick lookup: match your error text

What you seeMeaningJump to
failed to calculate checksum of ref ... not foundA COPY/ADD source file isn't in the build contextSection 2
failed to solve: failed to compute cache keyThe generic wrapper BuildKit puts around the error aboveSection 2
failed to solve: process "..." did not complete successfully: exit code: NA RUN command exited non-zeroSection 3
failed to resolve source metadataBuildKit couldn't fetch the FROM base image at allSection 4
failed to fetch oauth token / failed to fetch anonymous tokenRegistry auth handshake failed (private registry or rate limit)Section 4
failed to verify certificate: x509 ...TLS cert problem talking to a registrySection 4

2. "failed to calculate checksum of ref" / "failed to compute cache key"

This is the single most common docker build failure. It means a COPY or ADD instruction names a file or directory that does not exist in the build context (the directory you pass to docker build, not your whole filesystem). We wrote this Dockerfile in an otherwise-empty directory:

FROM alpine:latest
COPY nonexistent-file.txt /app/

Running docker build -t forever-guidetest:copy . against that directory gave:

#5 [2/2] COPY nonexistent-file.txt /app/
#5 ERROR: failed to calculate checksum of ref vdvaeexjgxbl2jy563csl2hvu::kddjrvrdpu2p8m21s3wrvvy2l: "/nonexistent-file.txt": not found
------
 > [2/2] COPY nonexistent-file.txt /app/:
------
Dockerfile:2
--------------------
   1 |     FROM alpine:latest
   2 | >>> COPY nonexistent-file.txt /app/
   3 |
--------------------
ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref vdvaeexjgxbl2jy563csl2hvu::kddjrvrdpu2p8m21s3wrvvy2l: "/nonexistent-file.txt": not found

Reading this: the bottom line, failed to solve: failed to compute cache key: failed to calculate checksum of ref ...: "/path": not found, is BuildKit's generic solve error wrapping the specific cache-key error, which itself wraps the real problem: the named path doesn't exist relative to the build context root. The ref vdvaeexjgxbl2jy563csl2hvu::... part is an internal BuildKit cache reference ID — ignore it, it's not useful for debugging, only the quoted path and "not found" matter.

Fix: check three things, in order: (1) the path is spelled correctly and relative to the build context (the last argument to docker build, often .), (2) the file isn't excluded by a .dockerignore file in that context, (3) if you're copying from a subdirectory, that you didn't forget to pass that subdirectory as the context (docker build -f sub/Dockerfile sub/, not just sub/Dockerfile .).

3. "failed to solve: process ... did not complete successfully: exit code: N"

This is a different failure: the Dockerfile and build context are fine, but a RUN command inside the build itself returned a non-zero exit code. We tested this directly:

FROM alpine:latest
RUN exit 1
$ docker build -t forever-guidetest:run1 .
...
#5 [2/2] RUN exit 1
#5 ERROR: process "/bin/sh -c exit 1" did not complete successfully: exit code: 1
------
ERROR: failed to build: failed to solve: process "/bin/sh -c exit 1" did not complete successfully: exit code: 1

Note what's different from Section 2: there's no "failed to compute cache key" in the middle. A failing RUN goes straight from failed to solve to process "..." did not complete successfully, because BuildKit got far enough to actually execute the step — it just failed while running, instead of failing to even start.

Fix: the command printed in quotes (/bin/sh -c exit 1 here) is the literal shell command BuildKit ran. Run that same command manually (in a container from the same base image, or locally) to see its real output above the Dockerfile's cached build log — BuildKit only shows the exit code by default, not the command's stdout/stderr, unless you add --progress=plain or the step wasn't cached.

4. Exit codes: the build surfaces your RUN command's own exit code

The number after exit code: is not a Docker error code — it's whatever your RUN command itself returned. We confirmed this by changing only the exit code:

FROM alpine:latest
RUN exit 42
#5 [2/2] RUN exit 42
#5 ERROR: process "/bin/sh -c exit 42" did not complete successfully: exit code: 42
------
ERROR: failed to build: failed to solve: process "/bin/sh -c exit 42" did not complete successfully: exit code: 42

Exit 1 produced "exit code: 1", exit 42 produced "exit code: 42" — nothing else in the message changed. This matters when a RUN calls a script or tool with meaningful exit codes (test runners, linters, package managers): the number in BuildKit's error is your direct clue to what actually failed inside that step, before you go looking at logs.

5. "failed to resolve source metadata" and registry/auth errors on FROM

These errors happen before BuildKit even starts your build — it's failing to fetch the FROM base image. We tested the fast, free case: a FROM referencing an image repository that doesn't exist at all (not just a bad tag):

FROM nonexistent-image-xyz123:doesnotexist
RUN echo hi
#2 [internal] load metadata for docker.io/library/nonexistent-image-xyz123:doesnotexist
#2 ERROR: pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
------
ERROR: failed to build: failed to solve: nonexistent-image-xyz123:doesnotexist: failed to resolve source metadata for docker.io/library/nonexistent-image-xyz123:doesnotexist: pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed

This is a distinct case from a bad tag on an image that does exist (covered in Docker Compose Up Errors, section 4, where alpine:bad-tag gives failed to resolve reference ... not found). When the repository name itself doesn't exist, the Hub's anonymous-pull auth layer rejects the token request first, so you get "pull access denied ... insufficient_scope" wrapped in "failed to resolve source metadata", not a plain "not found".

Three related messages we did not reproduce, because each needs a private registry with broken auth or an untrusted TLS setup, which this box doesn't have — per Docker/BuildKit's own docs and issue tracker, not measured here:

6. Checklist: narrowing down a build failure fast

Frequently asked questions

What does "failed to calculate checksum of ref" mean in a docker build?

It means a COPY or ADD instruction in your Dockerfile points at a file or directory that doesn't exist in the build context. We reproduced the exact text on Docker 29.8.1: ERROR: failed to calculate checksum of ref ...: "/path": not found. Fix the path, check your .dockerignore, and confirm you passed the right build context directory.

Why do I see "failed to solve" for some errors but "failed to compute cache key" for others?

failed to solve is BuildKit's generic top-level wrapper for any build failure. failed to compute cache key is a more specific wrapper that only appears for COPY/ADD source problems, because BuildKit fails while hashing the input for its cache, before it ever runs the step. A failing RUN command skips that phrase entirely and goes straight to "process ... did not complete successfully", because it did run, it just exited non-zero.

Does the exit code in a docker build error mean anything?

Yes. The number after "exit code:" is exactly the exit code your RUN command returned, not a Docker-specific code. We confirmed this directly: RUN exit 1 produced "exit code: 1" and RUN exit 42 produced "exit code: 42", with no other change in the message. Use that number as a direct clue to what failed inside the step (e.g. a specific tool's documented exit codes).

What's the difference between a bad image tag and a bad image name in docker build?

A bad tag on a real repository (e.g. alpine:typo-tag) gives "failed to resolve reference ... not found", because the registry confirms the repo exists but has no such tag. A bad repository name that doesn't exist at all gives a different error we measured: "failed to resolve source metadata ... pull access denied, repository does not exist or may require authorization: server message: insufficient_scope", because the anonymous-pull token request itself gets rejected before any tag lookup happens.

I'm getting an x509 certificate or oauth token error pulling my FROM image — how do I fix it?

These happen when BuildKit talks to a registry with broken or untrusted TLS, or a failing auth handshake (usually a private registry). Per Docker's own docs: for x509 "signed by unknown authority" errors, add the registry's CA certificate under /etc/docker/certs.d/<registry-host>/ca.crt rather than disabling verification. For oauth/anonymous token failures, check that the auth server for that registry is reachable and that credentials in ~/.docker/config.json aren't stale. We did not reproduce these directly since they need a real private registry with broken auth.

Written with AI assistance. Measured on 2026-10-02 with Docker 29.8.1 (BuildKit, containerd image store) on Linux, building from Dockerfiles under /tmp with image tags prefixed forever-guidetest. The real x509 certificate / OAuth token failure cases are from Docker's and BuildKit's own docs and GitHub issues, not measured, because reproducing them needs a private registry with broken auth. PlainHeaders is our extension; Docker and BuildKit are free.