Skip to main content
Detects COPY —from referencing a scratch stage with no file-producing instructions.
PropertyValue
SeverityError
CategoryCorrectness
DefaultEnabled

Description

Detects COPY --from=<stage> instructions where the source stage is FROM scratch and contains no ADD, COPY, or RUN instructions. Since scratch stages start with an empty filesystem, any COPY --from referencing such a stage is guaranteed to fail at build time. Common causes:
  • A stage was renamed or deleted during a refactor, leaving an empty placeholder
  • An AI patch accidentally removed the instructions that populated the stage
  • A COPY/RUN was moved to a different stage but the COPY --from reference wasn’t updated
Instructions like ENV, LABEL, EXPOSE, WORKDIR, and USER do not produce filesystem content and are not considered file-producing for this check.

Examples

Bad

# "artifacts" stage is scratch with no file-producing instructions
FROM scratch AS artifacts

FROM alpine:3.19
COPY --from=artifacts /out/app /usr/local/bin/app

Good

FROM golang:1.22 AS builder
RUN go build -o /out/app ./...

# "artifacts" stage has a COPY that populates it
FROM scratch AS artifacts
COPY --from=builder /out/app /out/app

FROM alpine:3.19
COPY --from=artifacts /out/app /usr/local/bin/app
  • tally/shell-run-in-scratch — a scratch stage with only a shell-form RUN is not considered empty by this rule (any RUN counts as file-producing). The shell-run-in-scratch rule warns about the failing RUN instead. If the user removes that RUN, this rule will then fire on downstream COPY --from references.

Configuration

[rules.tally.copy-from-empty-scratch-stage]
severity = "error"  # Options: "off", "error", "warning", "info", "style"