Dockerfile "COPY Failed: File Not Found" — Context, Not Paths

COPY/ADD can't find the file because Docker resolves paths against the build context, not the Dockerfile's directory or your shell's cwd. And .dockerignore can hide files you meant to copy.

What you'll see

Root causes

Build context isn't the directory you think

docker build . — the '.' is the context; all COPY paths are relative to it. Building from repo root while the Dockerfile expects to be in ./app/ makes every path miss. build path from CI checkouts differs for the same reason.

.dockerignore excludes the file

Over-broad patterns (e.g. '*' plus narrow un-ignores) silently drop the file from the context. COPY then can't see it — even though ls shows it right there.

Fix it

  1. Verify what the context actually contains
    docker build --no-cache --progress=plain -t debug-ctx . 2>&1 | grep -i 'transferring\|COPY' | head
  2. Check .dockerignore patterns against your path
    cat .dockerignore 2>/dev/null | grep -v '^#' ; # test: tar -cf - . -X .dockerignore | tar -tf - | grep <file>
  3. Set the context and Dockerfile explicitly in CI
    docker build -f docker/app.Dockerfile .   # context = repo root; COPY app/... paths match
  4. Local reproducibility: always build from the same directory the CI does
    ls -la <expected-context>/ ; pwd   # align 'docker build' invocation between local and CI

Field note

COPY can't reach outside the context — '../file' is a build error by design. If you need it, widen the context and adjust paths. Compose: the build: context is per-service in compose.yaml — check that, not the CLI default.

Common questions

Why does COPY ../file not work?

The build context is a security boundary: nothing outside it enters the image. Move the Dockerfile's context up (and adjust paths) instead of reaching out.

The file exists but COPY still can't find it. What else?

Check .dockerignore (the silent filter) and confirm the context root: run docker build with --progress=plain and read the 'transferring context' size — a suspiciously small transfer means your files never entered the context.

Ship it right the first time

A production-shaped compose stack: healthchecks, resource limits, log rotation. Never debug a boot race again.

Docker Production Starter — $19 →

One-time. Yours to modify. Instant download from the NinjaOps template store.