🐳 Reading Docker Build Errors
3 exercises — read real docker build failure output (BuildKit format) and identify the root cause: lockfile mismatches, bad image tags, and broken multi-stage copies.
Anatomy of a BuildKit error
=> ERROR [step N/total] ...— which build step failed- The
------block — the failing command's own stdout/stderr - The Dockerfile excerpt with
>>>— the exact line that failed - The final
ERROR: failed to solve: ...line — a one-line summary
Talking about it out loud (Slack / stand-up)
- "The build's failing at the
npm cistep — looks like a missing lockfile." - "It's failing to resolve the base image — I think the tag's misspelled."
- "The build itself passes, but the copy from the builder stage can't find the output directory."
- "Can you paste the full BuildKit error? I want to see which step it died on."
0 / 3 completed
1 / 3
docker build output — npm ci failure
{ex.passage} Read the build log. Why does the
RUN npm ci step fail with npm error code EUSAGE?Root cause: the lockfile was never copied into the build context before
Reading the Dockerfile excerpt at the bottom of the log: line 5 copies only
The fix: change
Log-reading tip: Buildx output shows the failing step with
npm ci ran.Reading the Dockerfile excerpt at the bottom of the log: line 5 copies only
package.json, then line 6 runs npm ci. Unlike npm install, npm ci is strict — it requires an existing package-lock.json (or npm-shrinkwrap.json) to install from, and refuses to run without one. The error npm error code EUSAGE means "you used this command incorrectly", not a network or registry problem.The fix: change
COPY package.json ./ to COPY package*.json ./ so both package.json and package-lock.json are copied before the install step. This is also a common Docker layer-caching pattern: copying just the manifest files first (before the rest of the source) lets Docker reuse the cached npm ci layer when only application code changes.Log-reading tip: Buildx output shows the failing step with
ERROR, then a ------ block with the command's own stderr, then the Dockerfile lines around the failure, then a final one-line summary starting with ERROR: failed to solve:. Read top to bottom in that order to go from "what command failed" to "why".