Docker Build Failed β How to Fix Common Docker Build Errors
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum
COPY failed: file not found in build context
RUN apt-get install: E: Unable to locate package
Docker builds fail for many reasons β missing files, network issues, permission problems, or Dockerfile logic errors. Hereβs every common cause with the fix.
How Docker builds work
When you run docker build ., Docker:
- Sends the build context (current directory minus
.dockerignore) to the daemon - Executes each Dockerfile instruction as a layer
- Caches layers β unchanged layers are reused from cache
Builds fail when a layer canβt execute: a file doesnβt exist in the context, a command returns non-zero, or a network request times out.
Fix 1: COPY/ADD β file not found in build context
The most common error. Docker can only access files within the build context (the directory you pass to docker build).
# β File doesn't exist or is excluded by .dockerignore
COPY config/production.json /app/config/
# ERROR: failed to compute cache key: "/config/production.json" not found
Checklist:
# 1. Does the file exist relative to the Dockerfile?
ls config/production.json
# 2. Is it excluded by .dockerignore?
cat .dockerignore | grep config
# 3. Are you building from the right directory?
docker build -f docker/Dockerfile . # Context is ".", not "docker/"
# 4. Is it a symlink? Docker doesn't follow symlinks outside the context
ls -la config/production.json
Fix:
# β
Ensure the path is relative to the build context (not the Dockerfile)
COPY ./config/production.json /app/config/
# β
If using a subdirectory Dockerfile, set context correctly
# docker build -f services/api/Dockerfile . β context is project root
Fix 2: apt-get β unable to locate package
The package index inside the base image is outdated or missing.
# β No package index available
RUN apt-get install -y curl git
# E: Unable to locate package curl
# β
Always update before installing
RUN apt-get update && apt-get install -y \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
Why rm -rf /var/lib/apt/lists/*? It removes the package index after installation, reducing the image size by 20-50MB.
For Alpine-based images:
# Alpine uses apk, not apt-get
RUN apk add --no-cache curl git
Fix 3: npm/yarn install fails
# β package.json not copied before npm install
COPY . .
RUN npm install # Fails if node_modules from host conflicts
# β
Copy package files first (also improves layer caching)
COPY package.json package-lock.json ./
RUN npm ci --production
COPY . .
Use npm ci instead of npm install in Docker β itβs faster, deterministic, and fails if package-lock.json is out of sync.
Common npm build failures:
# β Native dependencies need build tools
RUN npm install # node-gyp fails
# β
Install build dependencies first
RUN apt-get update && apt-get install -y python3 make g++ \
&& npm ci \
&& apt-get purge -y python3 make g++ \
&& rm -rf /var/lib/apt/lists/*
Fix 4: Build context too large (slow or OOM)
Sending build context to Docker daemon 2.5GB
# Build takes forever or runs out of memory
Fix: Create a .dockerignore file:
node_modules
.git
dist
build
*.log
.env
.venv
__pycache__
.next
coverage
Check context size:
# See what's being sent
du -sh $(docker build . 2>&1 | grep "Sending" | awk '{print $NF}') 2>/dev/null
# Or just check directory size minus .dockerignore
du -sh . --exclude=node_modules --exclude=.git
Fix 5: Permission denied during build
# β Script not executable
COPY start.sh /app/
RUN /app/start.sh # Permission denied
# β
Make it executable
COPY start.sh /app/
RUN chmod +x /app/start.sh
# β
Or set permissions in COPY (BuildKit)
COPY --chmod=755 start.sh /app/
For non-root users:
RUN adduser --disabled-password --gecos "" appuser
RUN chown -R appuser:appuser /app
USER appuser
Fix 6: Multi-stage build β file missing in final stage
Each FROM starts a fresh image. Files from previous stages donβt carry over automatically.
# Build stage
FROM node:20 AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build
# Production stage
FROM node:20-slim
WORKDIR /app
# β Forgot to copy build output β dist/ doesn't exist
CMD ["node", "dist/index.js"]
# β
Copy from builder stage
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
CMD ["node", "dist/index.js"]
Fix 7: Network errors during build
# β Network timeout during package install
RUN pip install -r requirements.txt
# Could not fetch URL https://pypi.org/simple/...
# β
Add retry logic
RUN pip install --retries 3 --timeout 60 -r requirements.txt
# β
Or use a mirror
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
If behind a corporate proxy:
docker build --build-arg HTTP_PROXY=http://proxy:8080 --build-arg HTTPS_PROXY=http://proxy:8080 .
Fix 8: Cache invalidation causing unnecessary rebuilds
# β Any change to source code invalidates npm install cache
COPY . .
RUN npm ci # Re-runs every time ANY file changes
# β
Copy dependency files first β only re-runs when they change
COPY package.json package-lock.json ./
RUN npm ci
COPY . . # Source changes don't invalidate npm cache
Order matters: Put instructions that change less frequently earlier in the Dockerfile.
Fix 9: Platform mismatch (ARM vs x86)
# β Building on M1/M2 Mac, deploying to x86 Linux
# Image works locally but crashes in production
# β
Specify target platform
docker build --platform linux/amd64 .
# β
Or use multi-platform build
docker buildx build --platform linux/amd64,linux/arm64 .
Debugging Docker builds
# Verbose output (see every command's output)
docker build --progress=plain .
# Build without cache (start completely fresh)
docker build --no-cache .
# Build up to a specific stage
docker build --target builder .
# Inspect a failed layer β run a shell in the last successful layer
docker run -it <last-successful-image-id> /bin/sh
FAQ
Why does my build work locally but fail in CI?
Common causes: different Docker version, no cache in CI (use --cache-from), network restrictions in CI environment, or files that exist locally but arenβt committed to git.
How do I reduce my Docker image size?
Use multi-stage builds, Alpine-based images, .dockerignore, and combine RUN commands. A typical Node.js app can go from 1GB to 100MB with these techniques.
Should I use COPY or ADD?
Use COPY unless you specifically need ADDβs features (auto-extracting tar files, fetching URLs). COPY is more predictable and preferred in almost all cases.
How do I fix βno space left on deviceβ during build?
docker system prune -a # Remove all unused images, containers, volumes
docker builder prune # Remove build cache