A misspelled stage name
Docker reads the target as an image and fails at the pull, so the error mentions the registry rather than the typo
FROM golang:1.22 AS builder RUN go build -o /app . FROM alpine COPY --from=bulider /app /app
Get the stage graph for a multi-stage Dockerfile: which stages reach the final image, which are dead, and whether every COPY --from resolves to a stage that exists above it.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Analyze. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
Docker reads the target as an image and fails at the pull, so the error mentions the registry rather than the typo
FROM golang:1.22 AS builder RUN go build -o /app . FROM alpine COPY --from=bulider /app /app
BuildKit skips it, so it is dead weight in the file rather than wasted build time
FROM alpine AS used RUN touch /a FROM alpine AS orphan RUN touch /b FROM alpine COPY --from=used /a /a
It is not in the final image and it is in the build cache, and --target on that stage hands it over
FROM alpine AS builder ENV NPM_TOKEN=REPLACE_ME RUN npm ci FROM alpine COPY --from=builder /app /app
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Docker reads an unrecognised --from target as an image reference, so the error is a failed pull. The credentials are fine and the stage name is wrong.
Instead:Check the --from target against the AS aliases in the file before touching anything to do with the registry.
The value is genuinely absent from the final image and genuinely present in the build cache layer, and --target on that stage produces a runnable image containing it.
Instead:Use RUN --mount=type=secret. It keeps the value out of every layer rather than relying on the layer being thrown away.
A stage nothing copies from may still be the --target of a test or lint job, which no part of the Dockerfile records.
Instead:Grep the pipeline for --target before deleting, and leave a comment on any stage that exists only for CI.
That one behaviour is why a graph is more useful here than a rule list. Docker cannot tell a misspelled stage from an image it has not heard of, so it tries to pull it.
There is no separate namespace for stage names. COPY --from=bulider is a valid instruction referring to an image called bulider, so the build fails at the pull with an authentication or not-found error. People then check their registry credentials, which are fine. The fix is a spelling correction three lines up.
File order is the order, and it is not inferred from the dependency graph. Referring to a stage defined lower down fails, and so does a stage copying from itself, which happens when two aliases get transposed during a refactor.
BuildKit builds only what the target needs, so a dead stage is skipped. The classic builder walks the file and builds all of them. Since BuildKit has been the default for a while this is mostly a readability problem now, with one exception: if CI builds with --target set past the dead stage, it does get built, so deleting it breaks a pipeline nobody reading this file can see.
This is worth being precise about, because the loose version of the advice is wrong. A credential set in a builder stage genuinely does not ship in the final image, so docker history on the pushed image will not show it. It is written into the build cache layer, and anybody who runs the build with --target pointed at that stage gets a runnable image containing it. RUN --mount=type=secret keeps it out of any layer at all, which is the difference that matters.
Docker does not reject it. A COPY --from naming that alias resolves to one of them, the build succeeds, and the wrong artefact is in the image. This is the failure mode with no error message attached, which is why it is worth checking for rather than waiting to notice.
Whether the build works, whether the copied paths exist, or how large the result is. It reads the text you paste, in your browser, and never runs Docker. Anything that looks like a credential is reported by key name with the value redacted.