Fix Docker Build Failures When Using Claude Code

Written by Michael Lip · Solo founder of Zovo · $400K+ on Upwork · 100% JSS Join 50+ builders · More at zovo.one

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:

  1. Build context issues: Files excluded by .dockerignore or not in the build context directory
  2. Layer ordering: Instructions depend on files that have not been copied yet
  3. Platform mismatch: Building for linux/amd64 on an ARM Mac (Apple Silicon)
  4. Dependency installation: Native modules that need build tools not present in the image
  5. Multi-stage references: Incorrect --from references 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

**Written by Michael** — solo dev, Da Nang, Vietnam. 50K+ Chrome extension users. $500K+ on Upwork (100% Job Success). Runs 5 Claude Max subs in parallel. Built this site with autonomous agent fleets. [See what I'm building →](https://zovo.one)

**Without a CLAUDE.md — what actually happens:** You type: "Add auth to my Next.js app" Claude generates: `pages/api/auth/[...nextauth].js` — wrong directory (you're on App Router), wrong file extension (you use TypeScript), wrong NextAuth version (v4 patterns, you need v5), session handling that doesn't match your middleware setup. You spend 40 minutes reverting and rewriting. Claude was "helpful." **With the Zovo Lifetime CLAUDE.md:** Same prompt. Claude reads 300 lines of context about YOUR project. Generates: `app/api/auth/[...nextauth]/route.ts` with v5 patterns, your session types, your middleware config, your test patterns. Works on first run. You commit and move on. That's the difference a $99 file makes. **[Get the CLAUDE.md for your stack →](https://zovo.one/lifetime?utm_source=ccg&utm_medium=cta-beforeafter&utm_campaign=claude-code-docker-build-failed-fix)**
This took me 3 hours to figure out. I put it in a CLAUDE.md so I'd never figure it out again. Now Claude gets it right on the first try, every project. 16 framework templates. Next.js, FastAPI, Laravel, Rails, Go, Rust, Terraform, and 9 more. Each one 300+ lines of "here's exactly how this stack works." Copy into your project. Done. **[See the templates →](https://zovo.one/lifetime?utm_source=ccg&utm_medium=cta-deploy&utm_campaign=claude-code-docker-build-failed-fix)** $99 once. Yours forever. I keep adding templates monthly.