Docker Error Guide: 'COPY failed: file not found in build context' Build Context Errors
Fix 'COPY failed: file not found in build context' in Docker: correct context-relative paths, .dockerignore exclusions, wrong build context, case sensitivity, and COPY --from.
- #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.
Guided workflow
Docker build: COPY failed, file not found
The file exists on disk and the build still cannot find it — almost always a build-context or .dockerignore problem, not a typo.
- Diagnose
- Inspect
- Interpret
- Remediate
- Validate
- Prevent
0 of 6 steps done
-
The message names a path that Docker could not resolve *inside the build context*. That is a different filesystem from your shell's working directory, and the gap between those two is the bug in most cases. Note the exact path it printed — you will compare it in a moment.
-
The build context is the directory you passed as the final argument to `docker build`, not the directory holding the Dockerfile. If those differ, every relative COPY path resolves somewhere you did not expect.
docker build -f Dockerfile .Read-onlyExpect: The trailing "." is the context. Confirm it is the directory you think.
What it means: A Dockerfile in ./docker/ built with context "." resolves COPY paths from the repository root, not from ./docker/.
cat .dockerignoreRead-onlyExpect: A list of exclusions.
What it means: A file excluded here is genuinely absent from the context. It exists on disk, the daemon never receives it, and the error is technically accurate.
find . -name "<the-file>" -not -path "./node_modules/*"Read-onlyWhat it means: Confirms where the file really is relative to the context root.
-
Four distinct problems produce this one message, and they have four different fixes. Compare the path the error printed against where the file actually sits relative to the context root, then match your case below.
- If: The file is listed in .dockerignore (or matched by a pattern there)
- The daemon never received it. Remove or narrow the pattern — note that `*` patterns exclude far more than people expect, and a negation must come after the exclusion it re-includes.
- If: The path is correct relative to the Dockerfile but not to the context
- COPY resolves against the context root. Either change the context argument, or write the path relative to that root.
- If: The file is generated by an earlier build step
- It does not exist at build time. Either generate it before `docker build` runs, or produce it inside an earlier stage and copy it with `COPY --from=<stage>`.
- If: It works locally and fails in CI
- CI probably did a shallow or partial checkout, or the file is gitignored and therefore absent from a clean clone. Check `git status --porcelain` and whether the file is tracked at all.
-
Change one thing and rebuild. Changing several at once means you will not know which mattered — and this error recurs often enough that knowing is worth something.
docker build --no-cache --progress=plain -f Dockerfile . 2>&1 | tail -40Read-onlyWhat it means: Plain progress output shows each layer and the exact resolved paths. `--no-cache` guarantees you are testing the change rather than a cached layer.
-
A build succeeding proves the COPY ran. It does not prove the file landed where the application expects it.
docker run --rm <image> ls -la <destination-path>Read-onlyExpect: The file, with a sensible size and mode.
What it means: A zero-byte file or a directory where you expected a file means the COPY succeeded but did something other than what you intended — a trailing slash on the destination changes the semantics.
-
Most recurrences of this error come from ambiguity about the context. State it: build from the repository root with an explicit `-f` path, keep `.dockerignore` narrow and commented, and make sure any generated file is produced by the build system before `docker build` is invoked — or inside a build stage where its provenance is visible.
Saves to your Toolkit when signed in, and to this browser otherwise.
Exact Error Message
A COPY (or ADD) instruction fails when its source path cannot be found in the build context. BuildKit reports it like this:
> [stage-0 3/5] COPY ./config/app.yaml /etc/app/app.yaml:
------
COPY failed: file not found in build context or excluded by .dockerignore: stat config/app.yaml: file does not exist
ADD produces the parallel message, and a multi-stage COPY --from surfaces a cache-key variant:
ADD failed: file not found in build context or excluded by .dockerignore: stat dist/release.tar.gz: file does not exist
failed to solve: failed to compute cache key: failed to calculate checksum of ref ...: "/app/dist": not found
What It Means
When you run docker build, Docker first sends a build context — the directory you pass as the final argument (usually .) — to the builder, minus anything matched by .dockerignore. Every COPY <src> <dst> and ADD <src> <dst> resolves <src> relative to the root of that context, not relative to the Dockerfile’s directory. If the file is not inside the transmitted context (because of the path, the context root, or a .dockerignore rule), Docker cannot stat it and the step fails. The or excluded by .dockerignore clause is a hint that the file may physically exist but was filtered out before the builder ever saw it.
Common Causes
- Path relative to the Dockerfile, not the context —
COPY ../shared/lib .fails because..escapes the context root; sources must live under the context. - File excluded by
.dockerignore— a broad pattern like*,config, ordistsilently strips the file from the context. - Wrong build context — running
docker build -f sub/Dockerfile .when the file is undersub/(so the context should besub/), or vice versa. - Case sensitivity —
COPY Config/app.yamlwhen the directory isconfig/; the Linux builder is case-sensitive even if your host filesystem is not. - File generated outside the context — an artifact built by CI into a directory that is not part of the context sent to Docker.
- Multi-stage
COPY --fromartifact missing — the earlier stage never produced the path being copied, yieldingfailed to compute cache key: ... not found. - Trailing-slash semantics —
COPY src dstwheredstlacks a trailing slash andsrcis multiple files, or a directory-vs-file mismatch.
How to Reproduce the Error
Reference a file that the .dockerignore excludes:
# Dockerfile
FROM alpine:3.20
COPY config/app.yaml /etc/app/app.yaml
# .dockerignore
config
docker build -t copy-demo .
COPY failed: file not found in build context or excluded by .dockerignore: stat config/app.yaml: file does not exist
The file exists on disk, but .dockerignore removed config from the context, so the builder cannot see it.
Diagnostic Commands
Re-run with plain progress to see exactly which path the builder tried to stat:
docker build --progress=plain --no-cache -t copy-demo . 2>&1 | grep -A3 'COPY\|ADD failed'
Inspect the .dockerignore rules that shape the context:
cat .dockerignore
List the actual contents of the context directory and the exact case of the target path:
ls -la ./config/
find . -iname 'app.yaml' -not -path './.git/*'
For a multi-stage copy, confirm the earlier stage produced the artifact by building just that target:
docker build --target build -t copy-demo:stage . && \
docker run --rm copy-demo:stage ls -la /app/dist
Check what the context actually transmits (size hints at over-broad inclusion):
du -sh . ; docker system df
Step-by-Step Resolution
1. Make the source path context-relative. The source must live under the context root. If you need files from a parent directory, move the build context up and point -f at the Dockerfile:
# Dockerfile in app/, but it needs ../shared
docker build -f app/Dockerfile -t app .
COPY shared/lib /opt/lib
COPY app/ /srv/app
2. Adjust .dockerignore. Stop excluding files you need to copy. Prefer narrow patterns and re-include with !:
**/node_modules
dist/tmp
!dist/release.tar.gz
3. Use the right build context. The final argument to docker build defines the context root. If the file is under sub/, either build with context sub/ or reference sub/file from a parent context:
docker build -f sub/Dockerfile -t app sub/
4. Fix case mismatches. Match the on-disk case exactly. COPY config/app.yaml (lowercase) if the directory is config, not Config.
5. Ensure generated artifacts are inside the context. Have CI write build outputs into the context directory before docker build, or copy them in. A file produced into /tmp outside the context will never be visible.
6. Fix multi-stage COPY --from. Confirm the source stage actually creates the path, and reference the stage by its AS name:
FROM node:20 AS build
WORKDIR /app
RUN npm run build # produces /app/dist
FROM nginx:1.27
COPY --from=build /app/dist /usr/share/nginx/html
7. Mind trailing-slash semantics. When copying a directory or multiple files, give the destination a trailing slash so Docker treats it as a directory: COPY src/ /app/src/.
How to Prevent the Issue
- Keep a tight, reviewed
.dockerignoreand add a comment next to any rule that could hide files aCOPYneeds. - Standardise the build context — always build from the repo root with
-f path/to/Dockerfileso paths are predictable. - Reference paths in lowercase and avoid relying on host case-insensitivity that the Linux builder does not share.
- In multi-stage builds, name every stage with
ASand copy by name, never by stage index. - Add a CI smoke build (
docker build --target build) that fails early if an expected artifact path is missing.
Related Docker Errors
failed to solve with frontend dockerfile.v0— the broader BuildKit solve error this often appears under; see the failed to solve guide.failed to compute cache key: ... not found— the multi-stage form of this same problem, covered above and in the failed-to-solve guide.no space left on devicewhile sending a large context — see the no space left on device guide.- More build fixes in the 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.
Stuck on this? Start guided troubleshooting
Open an interactive diagnostic session with this error already loaded. Work a step-by-step plan, record what each check returns, land on a root cause, and export a clean incident summary — no account needed to start.
Did this fix your issue?
Solved it a different way?
Share the fix that worked for you — reviewed, then published to help the next engineer.
That looks like it may contain a secret (key, token, password, or connection string). Please remove it — a note with a detected secret can’t be published.
Thanks — that helps. Published notes appear after a quick review.
Trending errors this week
The error guides other engineers are actually reading right now.
- 1mount: wrong fs type, bad option, bad superblock
- 2mount: wrong fs type, bad option, bad superblock
- 3Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block
- 4gpg: keyserver receive failed: No data
- 5Docker 'failed to set up container networking': Fix the Bridge and IP Pool
- 6Docker 'failed to create shim task': How to Fix the containerd Runtime Error
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.