This error occurs during Docker multi-stage builds when COPY --from cannot find the specified file or directory in the source stage. The fix involves verifying paths are correct, using absolute paths, and ensuring files are created in the expected locations during the build stage.
The "COPY failed: stat /var/lib/docker/overlay2/.../merged/...: no such file or directory" error occurs when Docker cannot locate a file or directory you're trying to copy, particularly during multi-stage builds with `COPY --from`. In multi-stage builds, you compile or build artifacts in one stage (e.g., a "builder" stage) and then copy only the necessary files to a smaller production image. This error indicates that the path specified in your COPY command doesn't exist in the source stage's filesystem. The overlay2 path in the error message is Docker's internal storage driver path and isn't something you interact with directly. The important part is "no such file or directory" which tells you Docker can't find what you're trying to copy.
Add a RUN ls command in your build stage to confirm the file is being created where you expect:
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Debug: List what was created
RUN ls -la /app/dist/If the ls command fails or shows no files, your build step isn't creating the expected output. Check your build command's output for errors.
Always use absolute paths when copying from another stage. WORKDIR from the source stage doesn't apply to your COPY command:
Wrong (relative path):
FROM node:18 AS builder
WORKDIR /app
RUN npm run build
# Creates files in /app/dist/
FROM nginx:alpine
# This fails - looks for ./dist in nginx image context
COPY --from=builder dist/ /usr/share/nginx/html/Correct (absolute path):
FROM node:18 AS builder
WORKDIR /app
RUN npm run build
FROM nginx:alpine
# Use absolute path from builder stage
COPY --from=builder /app/dist/ /usr/share/nginx/html/The key insight: COPY --from=builder dist/ looks for dist/ in the current stage's context, not the builder's WORKDIR.
Ensure the stage name in --from= matches your AS declaration exactly (case-sensitive):
# Stage named "builder" (lowercase)
FROM golang:1.21 AS builder
RUN go build -o /app/myservice
FROM alpine:3.18
# Must match exactly - "builder" not "Builder" or "build"
COPY --from=builder /app/myservice /usr/local/bin/You can also use numeric indexes (0-based):
FROM golang:1.21
RUN go build -o /app/myservice
FROM alpine:3.18
# --from=0 refers to the first stage
COPY --from=0 /app/myservice /usr/local/bin/Named stages are clearer and less error-prone than numeric indexes.
Understand how WORKDIR affects file locations:
FROM node:18 AS builder
# WORKDIR sets current directory to /app
WORKDIR /app
COPY . .
# npm run build creates files in /app/dist (relative to WORKDIR)
RUN npm run build
FROM node:18-slim
WORKDIR /app
# Source path is absolute from builder stage
# Destination path is relative to this stage's WORKDIR
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./Key points:
- The source path (after --from=builder) should be absolute
- The destination path is relative to the current stage's WORKDIR
- Each stage has its own independent WORKDIR
Environment variables are NOT expanded in COPY commands:
This won't work:
FROM golang:1.21 AS builder
ENV APP_DIR=/app
WORKDIR $APP_DIR
RUN go build -o $APP_DIR/myservice
FROM alpine:3.18
# $APP_DIR won't expand here!
COPY --from=builder $APP_DIR/myservice /usr/local/bin/Use hardcoded paths instead:
FROM golang:1.21 AS builder
WORKDIR /app
RUN go build -o /app/myservice
FROM alpine:3.18
COPY --from=builder /app/myservice /usr/local/bin/If you need dynamic paths, use ARG with default values:
ARG BUILD_DIR=/app
FROM golang:1.21 AS builder
WORKDIR /app
RUN go build -o /app/myservice
FROM alpine:3.18
COPY --from=builder /app/myservice /usr/local/bin/A common mistake is using CMD instead of RUN for build steps. CMD only runs when the container starts, not during the build:
Wrong - CMD doesn't execute during build:
FROM node:18 AS builder
WORKDIR /app
COPY . .
# CMD doesn't run during 'docker build'!
CMD ["npm", "run", "build"]
FROM nginx:alpine
# This fails - /app/dist was never created
COPY --from=builder /app/dist/ /usr/share/nginx/html/Correct - RUN executes during build:
FROM node:18 AS builder
WORKDIR /app
COPY . .
# RUN executes during 'docker build'
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist/ /usr/share/nginx/html/Remember:
- RUN: Executes during image build
- CMD: Executes when container starts
- ENTRYPOINT: Configures container as executable
Your .dockerignore might exclude files needed for the build:
# View your .dockerignore
cat .dockerignoreCommon problematic patterns:
# This excludes source files needed for build!
src/
*.ts
# This excludes config files
*.jsonA better approach - exclude only what you don't need:
# .dockerignore
node_modules
.git
.gitignore
*.md
Dockerfile
.dockerignore
.env*
coverage/
.nyc_output/If unsure, temporarily rename .dockerignore and rebuild to see if that's the issue:
mv .dockerignore .dockerignore.bak
docker build -t test .
mv .dockerignore.bak .dockerignoreSometimes cached layers cause stale state. Clean the build cache:
# Remove build cache
docker builder prune
# Build without using cache
docker build --no-cache -t myimage .
# For Docker Compose
docker compose build --no-cacheIn severe cases, a more thorough cleanup:
# Remove all unused images, containers, and cache
docker system prune -a
# Then rebuild
docker build -t myimage .Note: docker system prune -a removes all unused images, not just dangling ones. Use with caution in shared environments.
Understanding Docker's overlay2 storage driver: The overlay2 filesystem is Docker's default storage driver on Linux. Each layer of an image is stored in /var/lib/docker/overlay2/. The "merged" directory is a union mount of all layers. When you see overlay2 paths in error messages, Docker is telling you where it looked for the file in its internal storage.
Cross-compilation considerations: When building for different platforms (e.g., compiling Go for Linux on macOS), ensure your binary is built for the correct target:
FROM golang:1.21 AS builder
ENV CGO_ENABLED=0 GOOS=linux GOARCH=amd64
RUN go build -o /app/myserviceBuildKit and cache mounts: With BuildKit, you can use cache mounts to speed up builds while avoiding some COPY issues:
# syntax=docker/dockerfile:1
FROM node:18 AS builder
WORKDIR /app
RUN --mount=type=cache,target=/root/.npm \
npm ciDebugging with intermediate containers: You can run a shell in the build stage to investigate:
# Build up to the builder stage
docker build --target builder -t debug-builder .
# Explore the filesystem
docker run -it --rm debug-builder sh
ls -la /app/COPY vs ADD behavior: Both COPY and ADD can fail with this error. Key differences:
- COPY: Simple file/directory copy
- ADD: Can extract archives and fetch URLs (but avoid for simple copies)
Use COPY unless you specifically need ADD's extra features.
Symlinks and COPY: COPY follows symlinks and copies the target content. If your build creates symlinks, the actual files must exist:
# If build creates a symlink dist -> dist-v1.2.3
# COPY will try to copy dist-v1.2.3's contents
COPY --from=builder /app/dist/ /usr/share/nginx/html/image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker
Error response from daemon: failed to create the ipvlan port
How to fix 'failed to create the ipvlan port' in Docker
toomanyrequests: Rate exceeded for anonymous users
How to fix 'Rate exceeded for anonymous users' in Docker Hub