Fix Docker Build Failures When Using Claude Code
The Problem
You ask Claude Code to build your Docker image and it fails:
ERROR [build 4/7] RUN npm ci
#8 12.45 npm ERR! code ENOENT
#8 12.45 npm ERR! syscall open
#8 12.45 npm ERR! path /app/package.json
------
Dockerfile:12
--------------------
10 | WORKDIR /app
11 | COPY package*.json ./
12 | >>> RUN npm ci
--------------------
ERROR: failed to solve: process "/bin/sh -c npm ci" did not complete successfully: exit code: 1
Docker build errors can be cryptic. The failure might be a missing file, an architecture mismatch, a layer caching problem, or an incorrect build stage reference.
Quick Fix
Ask Claude Code to diagnose and fix:
My Docker build fails at the npm ci step. Read the Dockerfile,
check the build context, and fix the issue.
The most common causes:
# Wrong: .dockerignore excludes package.json
# Check .dockerignore for overly broad patterns
# Wrong: COPY before WORKDIR
COPY package*.json ./
WORKDIR /app # package.json is now in / not /app
# Right: WORKDIR first, then COPY
WORKDIR /app
COPY package*.json ./
RUN npm ci
What’s Happening
Docker builds execute instructions sequentially in an isolated environment. Each instruction creates a new layer. Common failure points include:
- Build context issues: Files excluded by
.dockerignoreor not in the build context directory - Layer ordering: Instructions depend on files that have not been copied yet
- Platform mismatch: Building for linux/amd64 on an ARM Mac (Apple Silicon)
- Dependency installation: Native modules that need build tools not present in the image
- Multi-stage references: Incorrect
--fromreferences in multi-stage builds
Step-by-Step Fix
Step 1: Read the full error output
Ask Claude Code to run the build with verbose output:
docker build --no-cache --progress=plain -t myapp . 2>&1
The --progress=plain flag shows all output instead of the condensed view, and --no-cache ensures you see the actual error, not a cached result.
Step 2: Fix .dockerignore conflicts
A common issue is .dockerignore excluding files needed during the build:
# Check what's being excluded
cat .dockerignore
Problematic .dockerignore:
# Too broad - excludes everything, then allowlists
*
!src/
!public/
# Missing: package.json, package-lock.json, tsconfig.json
Fixed .dockerignore:
node_modules
.git
.env
.env.local
dist
coverage
.next
*.md
.claude
Step 3: Fix a broken Dockerfile
Ask Claude Code to review and fix the entire Dockerfile:
Review my Dockerfile for issues. Check:
- Build context and .dockerignore compatibility
- Correct ordering of COPY and RUN instructions
- Multi-stage build references
- Security best practices (non-root user, minimal base image)
A well-structured Node.js Dockerfile:
# Build stage
FROM node:20-slim AS builder
WORKDIR /app
# Copy dependency files first (better layer caching)
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
# Copy source and build
COPY tsconfig.json ./
COPY src/ ./src/
RUN npm run build
# Production stage
FROM node:20-slim AS production
WORKDIR /app
# Install production dependencies only
COPY package.json package-lock.json ./
RUN npm ci --omit=dev --ignore-scripts && npm cache clean --force
# Copy built output from builder
COPY --from=builder /app/dist ./dist
# Security: run as non-root
RUN groupadd -r app && useradd -r -g app app
USER app
EXPOSE 3000
CMD ["node", "dist/index.js"]
Step 4: Fix platform/architecture issues
On Apple Silicon Macs, builds default to linux/arm64 but your deployment might need linux/amd64:
# Build for the correct platform
docker build --platform linux/amd64 -t myapp .
# Or use buildx for multi-platform
docker buildx build --platform linux/amd64,linux/arm64 -t myapp .
If native modules fail to compile, you may need build tools:
FROM node:20-slim
# Install build tools for native modules
RUN apt-get update && apt-get install -y \
python3 \
make \
g++ \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package*.json ./
RUN npm ci
Step 5: Fix layer caching issues
If builds are slow because dependencies reinstall every time:
# Bad: copying everything invalidates the npm ci cache
COPY . .
RUN npm ci
# Good: copy dependency files first, install, then copy source
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
The second approach caches the npm ci layer. It only re-runs when package.json or package-lock.json changes.
Step 6: Fix multi-stage build references
If you get “invalid from flag” or “not found” errors in multi-stage builds:
# Wrong: referencing a stage that doesn't exist
COPY --from=build /app/dist ./dist
# Error: "build" stage not defined
# Right: name your stages and reference them correctly
FROM node:20-slim AS build
WORKDIR /app
RUN npm run build
FROM node:20-slim AS production
COPY --from=build /app/dist ./dist
Step 7: Debug interactively
If the error is still unclear, ask Claude Code to create a debug build:
# Build up to the failing step
docker build --target builder -t myapp-debug .
# Run the debug image interactively
docker run -it myapp-debug /bin/sh
# Now you can inspect the filesystem
ls -la /app/
cat /app/package.json
Prevention
Add Dockerfile linting to your CI pipeline:
# Install hadolint
brew install hadolint
# Lint your Dockerfile
hadolint Dockerfile
Add Docker build instructions to your CLAUDE.md:
## Docker
- Build: `docker build -t myapp .`
- Run: `docker run -p 3000:3000 myapp`
- Always use multi-stage builds
- Never copy node_modules into the image
- Run as non-root user in production