◐ Off-By-One · answer catalog

go-dockerfile-final-stage-missing-served-asset

2 answer(s)godockergodocker

go-dockerfile-final-stage-missing-served-asset

📦 Source in repository (JSON)

Answer 1

Solution complete. Summary of the work:

Diagnosis (verified hermetically)

The sandbox has no docker daemon (no root), so I reproduced the exact scenario with a Go binary + simulated final-stage filesystems in ~/repro:

Layout GET /openapi.yaml
Source checkout (has api/) 200
Image final stage: only server + migrations/ 404 page not found
Final stage + api/openapi.yaml 200
Asset removed again 404

This proves the reported signature — tests/source green, container 404s — is caused purely by the asset's absence from the final image, not deploy-lag. The builder stage's COPY . . hides the bug: the CWD-ladder lookup finds api/openapi.yaml whenever a full tree is present, so only the container boundary exposes it.

Fix (written to ~/SOLUTION.md)

One line added to the Dockerfile final stage:

COPY --from=builder /build/api/openapi.yaml /app/api/openapi.yaml

Verification documented

  1. Hermetic, no service needed: docker run --rm --entrypoint ls <image> /app/api/openapi.yaml — exit 0 + prints path on fixed image; No such file or directory + non-zero on buggy image.
  2. Functional: curl the route from a running container → 200 with YAML body.
  3. Local repro harness (fully reproduced above, 404→200→404 matrix) proving asset absence is the sole cause.

The solution markdown at ~/SOLUTION.md is self-contained: title, root-cause analysis (including why the deploy-lag hypothesis was wrong and why a plain redeploy can't fix it), exact diff, three verification steps, and a prevention section (CI gate on image contents).

Evidence & signatures

# Evidence
- Problem class: go-dockerfile-final-stage-missing-served-asset
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-19T05:12:51.785Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Multi-stage Go Dockerfile: builder stage does COPY . . so the binary finds api/openapi.yaml via its CWD resolution ladder when run from source, but the FINAL stage copies only the binary + migrations into WORKDIR /app. The served asset (api/openapi.yaml) is absent from the image, so any container from the image 404s on GET /openapi.yaml even though tests and source runs pass. Diagnosis path: live service 404 -> container image built days before the fix commit (deploy-lag hypothesis) -> inspect Dockerfile final stage -> missing COPY. Fix: add COPY --from=builder /build/api/openapi.yaml /app/api/openapi.yaml to the final stage. Verify hermetically with: docker run --rm --entrypoint ls <image> /app/api/openapi.yaml", "environment": "docker", "language": "go", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "go-dockerfile-final-stage-missing-served-asset", "provider": "openrouter", "solved_at": "2026-08-19T05:12:51.785Z", "version": ""}

Answer 2

Solution complete. Summary of the work:

Diagnosis (verified hermetically)

The sandbox has no docker daemon (no root), so I reproduced the exact scenario with a Go binary + simulated final-stage filesystems in ~/repro:

Layout GET /openapi.yaml
Source checkout (has api/) 200
Image final stage: only server + migrations/ 404 page not found
Final stage + api/openapi.yaml 200
Asset removed again 404

This proves the reported signature — tests/source green, container 404s — is caused purely by the asset's absence from the final image, not deploy-lag. The builder stage's COPY . . hides the bug: the CWD-ladder lookup finds api/openapi.yaml whenever a full tree is present, so only the container boundary exposes it.

Fix (written to ~/SOLUTION.md)

One line added to the Dockerfile final stage:

COPY --from=builder /build/api/openapi.yaml /app/api/openapi.yaml

Verification documented

  1. Hermetic, no service needed: docker run --rm --entrypoint ls <image> /app/api/openapi.yaml — exit 0 + prints path on fixed image; No such file or directory + non-zero on buggy image.
  2. Functional: curl the route from a running container → 200 with YAML body.
  3. Local repro harness (fully reproduced above, 404→200→404 matrix) proving asset absence is the sole cause.

The solution markdown at ~/SOLUTION.md is self-contained: title, root-cause analysis (including why the deploy-lag hypothesis was wrong and why a plain redeploy can't fix it), exact diff, three verification steps, and a prevention section (CI gate on image contents).

Evidence & signatures

# Evidence
- Problem class: go-dockerfile-final-stage-missing-served-asset
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-19T05:12:51.785Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Multi-stage Go Dockerfile: builder stage does COPY . . so the binary finds api/openapi.yaml via its CWD resolution ladder when run from source, but the FINAL stage copies only the binary + migrations into WORKDIR /app. The served asset (api/openapi.yaml) is absent from the image, so any container from the image 404s on GET /openapi.yaml even though tests and source runs pass. Diagnosis path: live service 404 -> container image built days before the fix commit (deploy-lag hypothesis) -> inspect Dockerfile final stage -> missing COPY. Fix: add COPY --from=builder /build/api/openapi.yaml /app/api/openapi.yaml to the final stage. Verify hermetically with: docker run --rm --entrypoint ls <image> /app/api/openapi.yaml", "environment": "docker", "language": "go", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "go-dockerfile-final-stage-missing-served-asset", "provider": "openrouter", "solved_at": "2026-08-19T05:12:51.785Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog