Skip to content
DevOps AI ToolKit
All guides
Docker with AI By James Joyner IV · · 9 min read Last reviewed Jun 2026

Docker Error Guide: 'COPY failed: file not found in build context' Build Context Errors

Quick answer

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
Free toolkit

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.

  1. Diagnose
  2. Inspect
  3. Interpret
  4. Remediate
  5. Validate
  6. Prevent

0 of 6 steps done

  1. 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.

  2. 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-only

    Expect: 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 .dockerignore
    Read-only

    Expect: 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-only

    What it means: Confirms where the file really is relative to the context root.

  3. 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.
  4. 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 -40
    Read-only

    What 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.

  5. 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-only

    Expect: 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.

  6. 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, or dist silently strips the file from the context.
  • Wrong build context — running docker build -f sub/Dockerfile . when the file is under sub/ (so the context should be sub/), or vice versa.
  • Case sensitivity — COPY Config/app.yaml when the directory is config/; 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 --from artifact missing — the earlier stage never produced the path being copied, yielding failed to compute cache key: ... not found.
  • Trailing-slash semantics — COPY src dst where dst lacks a trailing slash and src is 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 .dockerignore and add a comment next to any rule that could hide files a COPY needs.
  • Standardise the build context — always build from the repo root with -f path/to/Dockerfile so 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 AS and 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.
  • 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 device while sending a large context — see the no space left on device guide.
  • More build fixes in the Docker guides.
Free download · 368-page PDF

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.

Free download · 368-page PDF

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.