Skip to content

Hotfix 0.47.10 — fix EACCES on /app/.next/cache in production#423

Closed
elfensky wants to merge 1 commit into
mainfrom
hotfix/0.47.10
Closed

Hotfix 0.47.10 — fix EACCES on /app/.next/cache in production#423
elfensky wants to merge 1 commit into
mainfrom
hotfix/0.47.10

Conversation

@elfensky

Copy link
Copy Markdown
Owner

Problem

The production container floods logs with:

Error: EACCES: permission denied, mkdir '/app/.next/cache'
    at async .../next/dist/server/lib/disk-lru-cache.external.js

Root cause: the Chainguard runtime (cgr.dev/chainguard/node:latest) has no nonroot entry in /etc/passwd — uid 65532 is named node. So the runner-stage COPY --from=builder --chown=nonroot:nonroot … lines silently fall back to root (0:0), leaving /app/.next root-owned (mode 755). The container runs as uid 65532, so the Next.js image optimizer's first remote-avatar optimization (mkdir('.next/cache/images'), triggered by Discord/GitHub/Google/Gravatar avatars) fails with EACCES and rejects on every subsequent cacheable image request.

Fix

Switch the three runner COPY lines to numeric --chown=65532:65532 (numeric IDs need no passwd lookup), so the runtime user owns the standalone tree and creates .next/cache on demand.

Verification

Reproduced the exact production state in a controlled build (/app/.next uid=0, mkdir FAILED:EACCES), then confirmed a real Dockerfile.app build with the numeric chown yields /app/.next uid=65532 and a successful .next/cache/images write. Probe against the deployed container showed /app/.next uid=0 / process uid=65532, matching the repro.

Scope / notes

  • Hotfix off main (v0.47.9 → v0.47.10); isolates the fix from the unreleased 0.48–0.52 work on develop. The same fix is already on develop as 0.52.1.
  • No application code or schema change. The image cache is ephemeral (Postgres holds all persistence).
  • Deploy note: after tagging, the server's docker-compose.yml must (1) bump the image pin to v0.47.10 (app + migrate), and (2) replace the curl healthcheck with the node-based one — Chainguard ships no curl, so the current override marks the container unhealthy.

🤖 Generated with Claude Code

…t/cache

The Chainguard runner (cgr.dev/chainguard/node:latest) has no `nonroot` entry
in /etc/passwd — uid 65532 is named `node` — so the runner-stage
`COPY --chown=nonroot:nonroot` lines silently fell back to root (0:0), leaving
/app/.next root-owned. The container runs as uid 65532, so the Next.js image
optimizer's mkdir('.next/cache/images') failed with EACCES and flooded logs
with unhandledRejection on every remote-avatar optimization.

Switch all three runner COPY lines to numeric --chown=65532:65532. Hotfix off
main (v0.47.10); the same fix is already on develop as 0.52.1. The runner COPY
change is identical to the develop fix, which was verified by building the real
image and confirming /app/.next is uid=65532 with a successful cache write.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@elfensky

Copy link
Copy Markdown
Owner Author

Superseded: releasing the full develop line (incl. this cache fix as 0.52.1) to main as v0.52.1 instead of an isolated hotfix. Closing in favor of the develop -> main release PR.

@elfensky elfensky closed this Jun 10, 2026
@elfensky elfensky deleted the hotfix/0.47.10 branch June 10, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant