Docker COPY Failed: Fix “File Not Found in Build Context”
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:
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:
docker build -f apps/web/Dockerfile apps/webapps/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:
| Invocation | Dockerfile source | Filesystem context | Can COPY read local files? |
|---|---|---|---|
docker build -f docker/Dockerfile . | docker/Dockerfile | . | Yes, if the source is in the context |
docker build - < Dockerfile | stdin | none | No; 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:
docker build -f apps/web/Dockerfile .the Dockerfile can use repository-root files:
FROM node:22-alpine AS buildWORKDIR /app
COPY package.json pnpm-lock.yaml ./COPY apps/web ./apps/webBut 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:
sed -n '1,240p' .dockerignoreThen 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 find | What it means |
|---|---|
apps/web/Dockerfile.dockerignore exists | Its patterns control the context for this Dockerfile |
Only .dockerignore exists at the context root | Those patterns control the context |
A broad rule and a later ! rule match | The 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:
for ignore_file in apps/web/Dockerfile.dockerignore .dockerignore; do if [ -f "$ignore_file" ]; then echo "== $ignore_file ==" sed -n '1,240p' "$ignore_file" fidoneA reliable diagnosis sequence
Use the same working directory and command that CI uses:
- Print the context. Identify the final path argument after all flags. Resolve it to an absolute directory.
- 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. - Read the active ignore file. Start with
<Dockerfile>.dockerignorebeside the selected Dockerfile; if it is absent, read.dockerignoreat the context root. - Check case exactly. Linux builders distinguish
Package.jsonfrompackage.json, even when a local macOS filesystem appears less strict. - Use one explicit build command. Do not debug a local root context while CI uses a subdirectory context.
- 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:
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:
docker build -f Dockerfile apps/webNow 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
../inCOPYto escape the context. Docker filters paths outside the context. - Do not move the Dockerfile and assume the context moved with it.
- Do not delete
.dockerignorewholesale 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:
Report a typo or broken link, or suggest a related topic.