1320 words
7 minutes

Docker COPY Failed: Fix “File Not Found in Build Context”

2026-08-14
2026-09-03
DevOps
Docker
/
DevOps
/
Containers
/
Troubleshooting

The Docker error COPY failed: file not found in build context has a narrow meaning: the source path is not available inside the build context, or a .dockerignore rule removed it before the build started. The Dockerfile’s directory is not automatically the context.

Fix the command first. The final positional path passed to docker build defines the context; -f only selects the Dockerfile. Once that boundary is correct, make the COPY source relative to the context root and check the context’s .dockerignore file.

The build command defines the context#

Docker’s build context documentation defines a context as the set of files the builder can access. In this command:

Terminal window
docker build -f docker/Dockerfile .

. is the context, so COPY can read files under the current repository directory. docker/Dockerfile is only the Dockerfile location.

In this command:

Terminal window
docker build -f apps/web/Dockerfile apps/web

apps/web is the context. A COPY package.json . instruction now looks for apps/web/package.json, while a source such as COPY package.json /app/ cannot read a package file that lives at the repository root. Moving the Dockerfile does not expand the files available to the builder.

That distinction explains many errors that look like a typo in COPY. If the source is outside the context, changing COPY ../package.json will not make it legal. Docker deliberately prevents a Dockerfile from reaching above the context boundary.

Do not confuse the Dockerfile with the context#

The final argument and -f can refer to different inputs. In particular, - can mean a Dockerfile read from stdin and leave the build with no filesystem context:

InvocationDockerfile sourceFilesystem contextCan COPY read local files?
docker build -f docker/Dockerfile .docker/Dockerfile.Yes, if the source is in the context
docker build - < DockerfilestdinnoneNo; use another stage, image, or named context

In the second command, the Dockerfile is piped as a text file and - is the context. A local file can exist beside the command and still be unavailable to COPY. If you need a Dockerfile from stdin, keep a filesystem path as the final context argument and verify that the command uses it.

Check .dockerignore before changing COPY#

Docker reads .dockerignore from the root of the build context. The file can exclude a path that exists on disk, so a repository listing alone is not enough to prove that Docker can copy it.

For example, with this layout:

.
├── .dockerignore
├── package.json
├── pnpm-lock.yaml
├── apps/
│ └── web/
│ ├── Dockerfile
│ └── src/

and this command:

Terminal window
docker build -f apps/web/Dockerfile .

the Dockerfile can use repository-root files:

FROM node:22-alpine AS build
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
COPY apps/web ./apps/web

But a .dockerignore rule such as apps/web or **/src can remove the exact source needed by the second COPY. Docker’s copy-ignored-file build check documents this failure mode explicitly: a COPY or ADD source that is excluded by .dockerignore is unavailable to the instruction.

Inspect the ignore file at the context root, not only beside the Dockerfile:

Terminal window
sed -n '1,240p' .dockerignore

Then check whether the pattern excludes the source or a parent directory. Remove or narrow the rule only if the file belongs in the image. Excluding secrets, local build output, and dependency directories is usually intentional; the fix is to copy the required source or build artifact explicitly, not to remove every ignore rule.

Check Dockerfile-specific ignore files#

The active ignore file can be beside the selected Dockerfile. With docker build -f apps/web/Dockerfile ., Docker uses apps/web/Dockerfile.dockerignore when it exists; that file takes precedence over .dockerignore at the context root. Inspect the file that matches the selected Dockerfile before assuming the root ignore file is active.

What you findWhat it means
apps/web/Dockerfile.dockerignore existsIts patterns control the context for this Dockerfile
Only .dockerignore exists at the context rootThose patterns control the context
A broad rule and a later ! rule matchThe last matching rule decides whether the path is included

For a quick comparison, replace the paths with the Dockerfile and context used by the failing build:

Terminal window
for ignore_file in apps/web/Dockerfile.dockerignore .dockerignore; do
if [ -f "$ignore_file" ]; then
echo "== $ignore_file =="
sed -n '1,240p' "$ignore_file"
fi
done

A reliable diagnosis sequence#

Use the same working directory and command that CI uses:

  1. Print the context. Identify the final path argument after all flags. Resolve it to an absolute directory.
  2. Locate the source from that root. If the Dockerfile says COPY apps/web/package.json ./, verify that the file is at <context>/apps/web/package.json.
  3. Read the active ignore file. Start with <Dockerfile>.dockerignore beside the selected Dockerfile; if it is absent, read .dockerignore at the context root.
  4. Check case exactly. Linux builders distinguish Package.json from package.json, even when a local macOS filesystem appears less strict.
  5. Use one explicit build command. Do not debug a local root context while CI uses a subdirectory context.
  6. Re-check the next COPY. Fixing the first missing source can expose another path that is outside the same boundary.

The Docker CLI reference describes the positional PATH, URL, or - argument as the build context and notes that paths outside it cannot be used by COPY. Keep that boundary in the build command rather than relying on a developer’s current directory by accident.

Choose a context that matches the build#

There are two common layouts, and each is valid when the COPY paths match it.

Repository-root context#

Use this for a monorepo or a build that needs a root lockfile:

Terminal window
docker build -f apps/web/Dockerfile .

The Dockerfile can copy package.json, a root lockfile, and apps/web using paths from the repository root. This is also the usual shape for an Astro static build that later serves output through Caddy; the Astro and Caddy Docker guide covers that multi-stage structure.

Application-directory context#

Use this when the application is self-contained:

Terminal window
docker build -f Dockerfile apps/web

Now every source path in the Dockerfile is relative to apps/web. COPY src ./src is valid, while COPY apps/web/src ./src points to a nested path that probably does not exist. If the application needs files from the repository root, either make the root the context or change the build inputs so the application is self-contained.

The right choice is the smallest context that contains all declared build inputs. A smaller context can also reduce accidental file exposure and transfer time, but do not claim that a smaller context alone fixes a missing file; the Dockerfile and ignore rules still have to agree.

Avoid the tempting fixes#

  • Do not use ../ in COPY to escape the context. Docker filters paths outside the context.
  • Do not move the Dockerfile and assume the context moved with it.
  • Do not delete .dockerignore wholesale just to make a build pass.
  • Do not make a local command use . while a deployment script uses a nested context.
  • Do not copy the entire repository when a specific source path or generated artifact is sufficient.

If the missing file is generated, make that generation step happen before docker build and verify the generated file is not ignored. If the file is a secret, inject it through the supported build or runtime secret mechanism rather than copying it into an image layer.

FAQ#

Q: Does Docker resolve COPY paths relative to the Dockerfile?#

A: No. COPY sources are resolved from the root of the build context. The -f option selects a Dockerfile but does not redefine that root.

Q: Why can Docker see a file locally but not in the build?#

A: The build may use a different context, or .dockerignore may exclude the file. Compare the exact command and inspect the ignore file at the context root.

Q: Can I copy a parent-directory file with COPY ../file?#

A: No. A Dockerfile cannot use COPY to reach outside its build context. Choose a context that contains the file or pass it into the build through an appropriate input.

Q: Should I remove .dockerignore to fix the error?#

A: Usually not. Find the rule excluding the required source and narrow it. Keep rules that prevent secrets, dependency folders, and unrelated local files from entering the context.

Q: What if Docker reads the Dockerfile from stdin?#

A: In docker build - < Dockerfile, - is the text-file context, so there is no filesystem context for local COPY. Pass a filesystem path as the final context argument or copy from another stage or named context.

References:

Docker COPY Failed: Fix “File Not Found in Build Context”
https://laplusda.com/en/posts/docker-copy-failed-file-not-found-build-context/
Author
Zero
Published at
2026-08-14
License
CC BY-NC-SA 4.0
Was this article useful?

Report a typo or broken link, or suggest a related topic.