Fix: Docker COPY Failed: File Not Found in Build Context
Part of: Docker, DevOps & Infrastructure
Quick Answer
How to fix 'COPY failed: file not found in build context', 'failed to read dockerfile', 'failed to calculate checksum', and other Docker build errors caused by missing files.
The Error
You run docker build and get one of these errors:
COPY failed: file not found in build contextERROR: failed to solve: failed to read dockerfile: open Dockerfile: no such file or directoryYou may also see these variations:
COPY failed: stat /var/lib/docker/tmp/docker-builder123456/some-file.txt: no such file or directoryADD failed: file not found in build contextfailed to compute cache key: failed to calculate checksum of "/some-file.txt": not foundAll of these mean the same thing: Docker cannot find a file you referenced in your Dockerfile. The file either doesn’t exist in the build context, is being excluded, or is referenced with the wrong path.
Why This Happens
When you run docker build ., the . at the end is the build context. Docker sends that entire directory to the Docker daemon, and every COPY and ADD instruction can only access files within that context. Nothing outside it exists as far as Docker is concerned.
Here’s what typically goes wrong:
- The file is outside the build context. You’re referencing a file that lives in a parent directory or somewhere not included in the context path.
.dockerignoreis excluding the file. Your.dockerignorehas a pattern that matches the file you’re trying to copy.- The source path in COPY/ADD is wrong. Paths in
COPYare relative to the build context root, not relative to the Dockerfile’s location. - The Dockerfile itself is not found. You’re running the build from a directory that doesn’t contain a
Dockerfile, or the file has a different name or casing.
How the Docker Build Context Works
This is the key concept. When you run:
docker build -t myapp .The . means “use the current directory as the build context.” Docker packages up everything in that directory and sends it to the daemon. Your COPY and ADD instructions can only reference files from within that package.
project/
├── Dockerfile
├── src/
│ └── app.js
├── package.json
└── config/
└── nginx.confIf you run docker build . from inside project/, these work:
COPY package.json . # ✅ file is in context root
COPY src/ ./src/ # ✅ directory is in context
COPY config/nginx.conf . # ✅ relative to context rootThese don’t:
COPY ../other-project/lib . # ❌ parent directory is outside context
COPY /home/user/secrets.env . # ❌ absolute path outside contextDocker cannot reach outside the build context. This is a security boundary, not a bug.
Fix 1: Check the Build Context
Make sure you’re running docker build from the right directory with the right context path.
The most common mistake is running the build from the wrong directory:
# You are in /home/user
docker build .
# But your Dockerfile and source code are in /home/user/myappFix: cd into the correct directory or specify the path:
docker build /home/user/myappIf your project structure requires the build context to be a parent directory, use the -f flag to point to the Dockerfile:
# Use parent directory as context, but specify Dockerfile location
docker build -f services/api/Dockerfile .Verify what’s in your build context. A quick way to see what Docker sees:
# List everything that would be included in the build context
# (minus .dockerignore exclusions)
ls -laFor a more precise check, you can temporarily add this to your Dockerfile:
FROM busybox
COPY . /context
RUN find /context -type fBuild it and you’ll see every file Docker has access to.
Why this matters: Docker cannot access files outside the build context. This is a security boundary, not a limitation. If Docker could reach parent directories or arbitrary host paths, a malicious Dockerfile could exfiltrate sensitive files from your system during a build.
Fix 2: Fix .dockerignore
Your .dockerignore file might be excluding the file you need. This is one of the most common causes and the hardest to spot.
Check your .dockerignore:
cat .dockerignoreA .dockerignore like this will cause problems:
# This excludes EVERYTHING, then only allows certain files back
*
!Dockerfile
!src/If you later add COPY package.json . to your Dockerfile, it will fail because package.json is excluded by the * rule.
Fix it by adding the file to the allow list:
*
!Dockerfile
!src/
!package.jsonCommon .dockerignore traps:
# This excludes all .env files, including ones you might need
*.env
# This excludes nested directories you might not expect
**/node_modules
**/dist
# This excludes everything starting with "build" -- including your build scripts
build*Tip: The .dockerignore file must be in the root of the build context. If you use -f to specify a Dockerfile in a subdirectory, the .dockerignore still needs to be at the context root. (BuildKit also supports a <Dockerfile>.dockerignore convention — e.g., docker/Dockerfile.dockerignore — but the standard location is the context root.)
Fix 3: Fix COPY/ADD Source Paths
Paths in COPY and ADD are relative to the build context root, not relative to the Dockerfile location. This catches people who put their Dockerfile in a subdirectory.
Given this structure:
project/
├── docker/
│ └── Dockerfile
├── src/
│ └── app.js
└── package.jsonIf you build with:
docker build -f docker/Dockerfile .Then inside docker/Dockerfile, paths are relative to project/ (the context root), not docker/:
# ❌ Wrong -- trying to go up from Dockerfile location
COPY ../src/app.js .
# ❌ Wrong -- using absolute path
COPY /src/app.js .
# ✅ Correct -- relative to build context root
COPY src/app.js .
COPY package.json .COPY paths never use .. to navigate relative to the Dockerfile. They always start from the build context root, regardless of where the Dockerfile is located.
Fix 4: Fix Dockerfile Location
If the error is specifically:
failed to read dockerfile: open Dockerfile: no such file or directoryDocker can’t find the Dockerfile itself. Common causes:
Wrong filename or casing:
ls Dockerfile*
# Is it named "dockerfile", "DockerFile", or "Dockerfile.dev"?Docker expects Dockerfile (capital D, no extension) by default.
Dockerfile is in a subdirectory:
# Tell Docker where the Dockerfile is
docker build -f path/to/Dockerfile .You’re in the wrong directory:
pwd
# Make sure you're where you think you are
ls DockerfileFix 5: Check Case Sensitivity
Docker builds on Linux use a case-sensitive filesystem. If you develop on macOS or Windows (case-insensitive by default), a build might work locally but fail in CI or on a Linux build server because of casing mismatches.
# Your file is named "Readme.md"
COPY README.md . # ❌ fails on Linux -- "README.md" ≠ "Readme.md"Check the exact casing of your files:
ls -laThis also applies to directory names:
COPY Src/ ./src/ # ❌ if the directory is actually named "src/"
COPY src/ ./src/ # ✅Fix the casing in your Dockerfile to match the actual filenames exactly.
Edge Cases
Multi-stage builds and COPY —from
In a multi-stage build, COPY --from copies from a previous build stage, not from the build context:
FROM node:20 AS builder
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
# This copies from the "builder" stage, not the build context
COPY --from=builder /app/dist /usr/share/nginx/htmlIf you get a “file not found” error on a COPY --from line, the problem is in the earlier stage. The file wasn’t created where you expected. Add a RUN ls -la /app/dist after your build step in the builder stage to verify the files exist.
You can also copy from external images:
COPY --from=nginx:alpine /etc/nginx/nginx.conf /etc/nginx/nginx.confIf this fails, the file path inside that image may have changed between versions.
Symlinks
Docker does not follow symlinks that point outside the build context. If you have:
project/
├── Dockerfile
├── config -> /etc/shared/config # symlink to outside the contextCOPY config/ . will fail because the symlink target is outside the build context. Copy the actual files into your project directory instead, or mount them at runtime with -v.
Git submodules not cloned
If your project uses git submodules and you cloned without --recurse-submodules, those directories will be empty:
git clone https://github.com/user/repo.git
# submodule directories exist but are empty
docker build .
# COPY libs/shared-utils/ . → fails, directory is emptyFix:
git submodule update --init --recursiveThen rebuild.
Docker BuildKit vs legacy builder
The error messages differ depending on which builder you’re using.
Legacy builder:
COPY failed: stat /var/lib/docker/tmp/docker-builder123456/myfile: no such file or directoryBuildKit (default since Docker 23.0):
failed to compute cache key: failed to calculate checksum of "/myfile": not foundBoth mean the same thing — the file isn’t in the build context. BuildKit is now the default, so if you’re searching Stack Overflow and see the older stat /var/lib/docker/tmp error format, the same fixes apply.
You can explicitly switch between them:
# Force BuildKit
DOCKER_BUILDKIT=1 docker build .
# Force legacy builder (if still available)
DOCKER_BUILDKIT=0 docker build .Version history: BuildKit vs legacy builder behavior
The default builder switched from the legacy builder to BuildKit when Docker Engine 23.0 shipped in early 2023. This change altered several behaviors that are not obvious from the changelog. Knowing what changed makes it much easier to debug “the same Dockerfile worked last year but not now” issues.
- Context streaming. The legacy builder sent the entire context up front:
Sending build context to Docker daemon 250MB. BuildKit only streams the files actually referenced byCOPYandADD. This is faster, but it also means a missing.dockerignorerule that mattered for performance under the legacy builder may not matter under BuildKit — yet a.dockerignoretypo that excludes a needed file fails identically on both. .dockerignoreper-Dockerfile lookup. BuildKit checks for<Dockerfile-name>.dockerignorenext to the Dockerfile first, then falls back to the context-root.dockerignore. The legacy builder only ever reads the context-root file. If you split your project intoDockerfile.apiandDockerfile.web, BuildKit lets you keep per-Dockerfile ignore lists; the legacy builder does not.- Cache scope. BuildKit produces a different layer cache format and stores it under
/var/lib/docker/buildkit/. Runningdocker builder pruneclears it. Adocker system prunedoes not clear BuildKit cache by default in some older versions — pass--alland--volumesif you need a full wipe. - Symlink handling. Both builders refuse to follow symlinks that point outside the context, but BuildKit’s error message is
failed to compute cache keyinstead offorbidden path outside the build context. Same behavior, different wording. - Heredoc support. BuildKit accepts
<<EOFheredocs inRUNandCOPYinstructions (with the# syntax=docker/dockerfile:1.4directive). Legacy builder rejects them as syntax errors. If you copy a modern Dockerfile from a tutorial and get a parse error, you may be on the legacy builder. - Output destination. BuildKit can output the build result somewhere other than the local image store via
--output. The legacy builder cannot. If a tutorial referencesdocker buildx build --output type=local,dest=./out, it assumes BuildKit.
If you maintain CI pipelines that pin an older Docker Engine (for example, Docker 20.10 LTS), the legacy builder may still be the default there. Force BuildKit explicitly with DOCKER_BUILDKIT=1 or migrate to docker buildx, which is BuildKit-native. Conversely, if a legacy-era Dockerfile uses behaviors that BuildKit handles differently (relying on full-context streaming, depending on the absence of <Dockerfile>.dockerignore lookup), test the build under both before switching CI.
Still Not Working?
Clear Docker build cache
Docker caches build layers aggressively. If you’ve fixed the file issue but still get the error, a stale cache may be the culprit:
docker build --no-cache -t myapp .To clear the entire build cache:
docker builder pruneWSL2 file path issues
If you’re using Docker Desktop with WSL2 on Windows, file paths between the Windows filesystem and WSL2 can cause problems.
Key rule: Keep your project files inside the WSL2 filesystem (/home/user/...), not on the Windows mount (/mnt/c/...). Files on the Windows mount are accessed through a translation layer that can cause path resolution issues, and build performance is significantly worse.
# ❌ Slow and can cause path issues
cd /mnt/c/Users/me/projects/myapp
docker build .
# ✅ Fast and reliable
cd ~/projects/myapp
docker build .If you must use files from the Windows filesystem, make sure Docker Desktop has the correct WSL2 integration enabled under Settings > Resources > WSL Integration.
Permission denied on COPY
If the file exists but you get a permission error during COPY:
failed to solve: failed to read dockerfile: permission deniedCheck the file permissions:
ls -la Dockerfile
# Make sure it's readable
chmod 644 DockerfileThis can also happen if Docker doesn’t have access to the directory. On SELinux-enabled systems (Fedora, RHEL), you may need to adjust the security context. If the permission error is about the Docker socket itself, see Fix: Docker permission denied on the daemon socket.
Large build context slowing builds
If your build takes a long time before it even starts, Docker is sending a massive build context to the daemon. You’ll see:
Sending build context to Docker daemon 2.5GBThis usually means node_modules, .git, or large data directories are being included. Fix it with a proper .dockerignore:
node_modules
.git
*.log
dist
.next
.cache
tmp
coverageA good .dockerignore can cut your build context from gigabytes to megabytes and dramatically speed up builds. For a deeper look at oversized contexts and how to diagnose them, see Fix: Docker build context too large.
BuildKit secrets and SSH mounts fail differently
If you use RUN --mount=type=secret,id=mysecret or --mount=type=ssh, missing secrets surface as “file not found” rather than a clear “secret not provided” message. Confirm the secret was passed at build time:
docker buildx build --secret id=mysecret,src=./secret.txt .If ./secret.txt does not exist on the host, BuildKit raises a file-not-found error that looks indistinguishable from a normal COPY failure. The fix is to verify the host path before building. See also Fix: Docker image not found when the failure happens during a --from=<image> reference instead.
COPY —link surprises
BuildKit added COPY --link and ADD --link as part of Dockerfile syntax 1.4. With --link, the copied layer is created independently of the previous layers, which makes rebuilds faster. The catch: if the source path is wrong, the error message is even less specific than the default (“failed to solve” with no layer hint). When debugging a COPY --link failure, temporarily remove --link to get a clearer error, then add it back once the path is verified.
Building from a remote URL or Git context
docker build https://github.com/user/repo.git and similar remote contexts have their own caveats. Files inside the repo are accessible relative to the repo root, not your local disk. If a COPY references a local file like COPY ./local-secret.env ., that path does not exist inside the remote context and the build fails. Use a local clone or pass build arguments instead. Submodules in remote contexts also require the #branch:path syntax or a pre-cloned local copy — see the section above on git submodules.
Multi-stage build failing on a later stage
If COPY --from=builder fails even though the builder stage looks fine, dig into the builder stage itself. A failure in the build step (RUN npm run build) may produce an empty dist/ directory without aborting the stage, so the later COPY --from=builder /app/dist /usr/share/nginx/html finds nothing. Add RUN ls -la /app/dist || (echo "build output missing" && exit 1) after the build step to make the failure explicit. See Fix: Docker multi-stage build failed for more on diagnosing layered build errors.
Related: Fix: Docker Permission Denied While Trying to Connect to the Docker Daemon Socket
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Docker Container Keeps Restarting
How to fix a Docker container that keeps restarting — reading exit codes, debugging CrashLoopBackOff, fixing entrypoint errors, missing env vars, out-of-memory kills, and restart policy misconfiguration.
Fix: Docker Compose Environment Variables Not Loading from .env File
How to fix Docker Compose not loading environment variables from .env files — why variables are empty or undefined inside containers, the difference between env_file and variable substitution, and how to debug env var issues.
Fix: Cannot Connect to the Docker Daemon. Is the Docker Daemon Running?
How to fix the 'Cannot connect to the Docker daemon' error on Linux, macOS, and Windows, including Docker Desktop, systemctl, WSL2, and Docker context issues.
Fix: Docker Volume Permission Denied – Cannot Write to Mounted Volume
How to fix Docker permission denied errors on mounted volumes caused by UID/GID mismatch, read-only mounts, or SELinux labels.