docker failed to compute cache key: failed to calculate checksum of ref - not found (the 6 causes, tested on Docker 28)

TL;DR

  • "failed to compute cache key ... not found" is COPY telling you the source path is not in the build context. It happens before any layer is built, which is why --no-cache changes nothing.
  • The context is the last argument of docker build, not the folder with the Dockerfile. cd docker && docker build . sends only the docker/ folder; docker build -f docker/Dockerfile . from the project root is the fix.
  • The six causes I reproduced: a typo in the file name, the wrong context directory, a .dockerignore rule, wrong letter case (App.py vs app.py), a multi-stage COPY --from path that does not exist in that stage, and the same mistakes on the legacy builder, which words it as COPY failed: file not found in build context or excluded by .dockerignore.
  • See what BuildKit really received: a two-line throwaway Dockerfile with COPY . /ctx and RUN find /ctx -type f lists the context.
  • Every output below is from Docker 28.0.4 with BuildKit (buildx 0.38) on Ubuntu 24.04, captured on 2026-10-15.

COPY reads the build context, not your disk - the five ways a file ends up not found

I first wrote this post after hitting the error on my Windows laptop in 2021: my Dockerfile lived in a sub-folder and I ran docker build from inside it. That is still the most common cause. But when I reproduced it properly on Docker 28 for this rewrite, I found five more ways to get the identical message, and one case where BuildKit quietly does something you did not ask for. All six are below with their real output.

Table of Content

  1. What the error means
  2. Cause 1: the file name is wrong
  3. Cause 2: you built from the wrong directory
  4. Cause 3: dockerignore excluded the file
  5. Cause 4: letter case
  6. Cause 5: multi-stage COPY --from path
  7. Cause 6: the legacy builder, and why --no-cache does not help
  8. Two commands that show what the context contains
  9. What broke when I ran this
  10. Conclusion

1. What the error means

CauseError text (Docker 28.0.4)Fix
typo in COPY source"/main.py": not foundmatch the name in the context
wrong context dir"/app.py": not found from cd docker && docker build .docker build -f docker/Dockerfile . from the root
.dockerignore"/app.py": not found while the file is on diskfix the pattern, or add !app.py
letter case"/App.py": not foundLinux paths are case-sensitive, even when your Mac or Windows is not
multi-stage path"/src/dist": not found on COPY --from=builduse the path the earlier stage really produced
legacy builderCOPY failed: file not found in build context or excluded by .dockerignoresame fixes; the text is just older

BuildKit computes a checksum of every COPY and ADD source before it runs anything, so it can decide whether a cached layer can be reused. That is the "cache key". A source that does not exist in the context has no checksum, so the build stops at that line with not found. The Dockerfile COPY reference states the rule in one sentence: the source path is relative to the build context.


2. Cause 1: the file name is wrong

My project has app.py and requirements.txt. The Dockerfile asks for main.py:

1FROM python:3.12-alpine
2WORKDIR /app
3COPY requirements.txt .
4COPY main.py .
5CMD ["python","main.py"]
1$ docker build -q -t ck:1 .
2Dockerfile:4
3--------------------
4   2 |     WORKDIR /app
5   3 |     COPY requirements.txt .
6   4 | >>> COPY main.py .
7   5 |     CMD ["python","main.py"]
8--------------------
9ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref 6134b6ae-8eb1-4f62-889e-a360c80bcfbf::u1tatgayj8t94v575ydb9luf2: "/main.py": not found

BuildKit points at the exact line (>>> COPY main.py .) and names the missing path at the end. The long ref identifier in the middle is the context snapshot; ignore it, the useful part is always the quoted path after it.


3. Cause 2: you built from the wrong directory

This was my original 2021 mistake. The Dockerfile sits in docker/, so I changed into that folder and built:

1$ cd docker && docker build -q -t ck:2 .
2Dockerfile:3
3--------------------
4   1 |     FROM python:3.12-alpine
5   2 |     WORKDIR /app
6   3 | >>> COPY app.py .
7--------------------
8ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref 6134b6ae-8eb1-4f62-889e-a360c80bcfbf::q6kp0t1cxlus5luq9sfah8abl: "/app.py": not found

app.py exists, one level up. But the context is ., which is now docker/, and app.py is not in it. Keep the context at the project root and point -f at the Dockerfile:

1$ docker build -q -t ck:2 -f docker/Dockerfile .
2sha256:9365c8363f0184f75d5ad8ee5736c90dad8bbecea6b7329d5a8c100ab62a2e6e

Docker's build context documentation is explicit: the context and the Dockerfile location are two independent things.


4. Cause 3: dockerignore excluded the file

The file is on disk, the context is right, and the build still fails:

1$ docker build -q -t ck:3 .
2ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref 6134b6ae-8eb1-4f62-889e-a360c80bcfbf::3ta980nno2bjqfdzxajl1lskj: "/app.py": not found
3
4$ cat .dockerignore
5*.py

.dockerignore is applied when the context is sent, so an excluded file is simply absent as far as BuildKit is concerned. A negation line keeps the file you need:

1$ printf '*.py\n!app.py\n' > .dockerignore
2$ docker build -q -t ck:3 .
3sha256:9365c8363f0184f75d5ad8ee5736c90dad8bbecea6b7329d5a8c100ab62a2e6e

The same image ID as the successful build in cause 2, because the context content is now identical. Patterns like *, **/node_modules or .git in a copied-in .dockerignore are a classic way to lose a file you need; the syntax is documented on the dockerignore page.


5. Cause 4: letter case

On macOS and Windows, App.py and app.py are the same file. Inside the build they are not:

1$ docker build -q -t ck:4 .
2   3 | >>> COPY App.py .
3ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref 6134b6ae-8eb1-4f62-889e-a360c80bcfbf::om2yunn1mi7kovnp8jd6v7rrg: "/App.py": not found

The context is a Linux filesystem on the builder, and the file is app.py. Match the case exactly.


6. Cause 5: multi-stage COPY --from path

In a multi-stage build the "context" for COPY --from=build is the filesystem of that stage, and the error wording is identical:

1FROM node:22-alpine AS build
2WORKDIR /src
3RUN mkdir -p build && echo "<h1>hi</h1>" > build/index.html
4FROM nginx:1.27-alpine
5COPY --from=build /src/dist /usr/share/nginx/html
1$ docker build -q -t ck:6 .
2   5 | >>> COPY --from=build /src/dist /usr/share/nginx/html
3ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref 6134b6ae-8eb1-4f62-889e-a360c80bcfbf::ud8d6fq2vdjaarxf0ti4ebmnm: "/src/dist": not found

The first stage wrote to build/, the second asked for dist/. This one bites when you change a framework's output folder (Vite uses dist, Create React App used build) and forget the Dockerfile. With the path corrected, the build passes:

1$ docker build -q -t ck:6 .
2sha256:1db0cfb3c8988f70bbd8aebef733324d5c57d88a864afb0a703d9582eb50a0a2

7. Cause 6: the legacy builder, and why --no-cache does not help

With DOCKER_BUILDKIT=0 the same typo produces the older message many forum answers quote:

1$ DOCKER_BUILDKIT=0 docker build -q -t ck:8 .
2DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
3Sending build context to Docker daemon  7.168kB
4Step 3/3 : COPY main.py .
5COPY failed: file not found in build context or excluded by .dockerignore: stat main.py: file does not exist

That wording is more helpful - it even mentions .dockerignore - but it is the same problem. And because the failure happens while BuildKit is computing the cache key, clearing the cache cannot fix it:

1$ docker build --no-cache -q -t ck:8 .
2ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref 6134b6ae-8eb1-4f62-889e-a360c80bcfbf::ickrbqd70hholx8h76pmkklya: "/main.py": not found

If you reached for --no-cache or docker builder prune, stop: the word "cache" in the message is misleading. The file is missing.


8. Two commands that show what the context contains

When none of the causes above is obvious, list the context exactly as BuildKit sees it. This throwaway Dockerfile copies everything and prints it:

1$ printf "FROM alpine:3.20\nCOPY . /ctx\nRUN find /ctx -type f | sort\n" > Dockerfile.ctx
2$ docker build --no-cache --progress=plain -f Dockerfile.ctx . 2>&1 | grep -E "^#[0-9]+ [0-9.]+ /ctx"
3#7 0.141 /ctx/Dockerfile
4#7 0.141 /ctx/Dockerfile.ctx
5#7 0.141 /ctx/app.py
6#7 0.141 /ctx/docker/Dockerfile
7#7 0.141 /ctx/requirements.txt
8#7 0.141 /ctx/static/a.txt

If the file you are copying is not in that list, the cause is the context directory or .dockerignore. If it is in the list, the cause is the spelling or case in your COPY line. The whole context here was 7.168 kB, and BuildKit reported the Dockerfile load DONE at 0.0 s, the context transfer DONE at 0.0 s, the base image DONE at 0.5 s and the find output at 0.141 s, so this check costs nothing; on a project with a node_modules folder, add that folder to .dockerignore first or the listing will be enormous.


9. What broke when I ran this

All of this ran as a script on a fresh GitHub Actions runner (Ubuntu 24.04, Docker 28.0.4) on 2026-10-15. Two results were not what I expected.

1. COPY ../requirements.txt . did not fail. I added it as "cause 5: copying from outside the context", expecting a forbidden path outside the build context error. Instead the build succeeded. BuildKit normalises the source path against the context root, so ../requirements.txt became /requirements.txt, which exists in my context. The copy "worked" only because a file with that name happened to be at the root; if it had not, the error would have been the usual not found. The lesson is that .. never reaches outside the context, and it never errors either, so a parent-directory path in a COPY line is always a bug waiting to be noticed.

2. COPY static/* /app/static/ and COPY static /app/static2 produced the same result. I expected the glob form to flatten or fail; both copied a.txt into the target directory. The difference only appears when static contains sub-directories, where the glob copies their contents but not the directories themselves. Not an error, but worth knowing when a sub-folder "disappears" after a copy.


10. Conclusion

failed to compute cache key ... not found is a missing file in the build context. To summarise:

  1. Read the quoted path at the end of the error; BuildKit names exactly what it could not find.
  2. Check the context: it is the last argument of docker build, minus .dockerignore. Build from the project root with -f pointing at the Dockerfile.
  3. Check spelling and letter case, and in multi-stage builds check the path the earlier stage really produced.
  4. Do not clear the cache; the problem is not cached.

If the file copies but the container then cannot find it at runtime, Docker COPY vs ADD explains the destination side, and if the error is about a source with no matching files at all, see COPY failed: no source files were specified. For the image tag errors that often follow a fixed build, see docker: invalid reference format.

Did this save you a debugging session? Stay in the loop -

Posts in this series