From 82241063f67e62f5af85152085022d9c0c09f377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 17 May 2026 23:56:04 +0200 Subject: [PATCH] fix(app-error): auto-recover from stale-shell ChunkLoadError MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a deploy the cached SPA shell still references the old chunk filenames. Next.js fetches them, the new server 404s the request, and the user sees the generic error surface — typically with no context other than "Failed to load chunk". The fix on the user's side is a hard reload; before this commit they had to discover it themselves. `AppError` now detects the chunk-load family of errors (`ChunkLoadError`, `Loading chunk`, `Failed to load chunk`, `Failed to fetch dynamically imported module`) and triggers a single `window.location.reload()`. `sessionStorage` gates the auto-reload to once per session so an unrecoverable error doesn't loop into a reload storm. Browsers in strict-privacy mode fall through to the error UI cleanly. --- src/app/error.tsx | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/app/error.tsx b/src/app/error.tsx index b1a20f6ba..0077dc484 100644 --- a/src/app/error.tsx +++ b/src/app/error.tsx @@ -3,6 +3,19 @@ import { useEffect } from "react"; import { ErrorDetails } from "@/components/error-details"; +const CHUNK_RELOAD_KEY = "healthlog:chunk-reload-attempted"; + +function isChunkLoadError(err: Error & { digest?: string }): boolean { + if (err.name === "ChunkLoadError") return true; + const msg = err.message ?? ""; + return ( + msg.includes("Loading chunk") || + msg.includes("Loading CSS chunk") || + msg.includes("Failed to load chunk") || + msg.includes("Failed to fetch dynamically imported module") + ); +} + export default function AppError({ error, reset, @@ -18,6 +31,25 @@ export default function AppError({ }; g.__healthlog_onError?.(error); } + + // v1.4.38.3 — auto-recover from a stale-shell chunk-load error. + // After a deploy the cached shell still references old chunk + // filenames; they 404 and Next.js surfaces them as `ChunkLoadError`. + // A single hard reload fetches the new shell + chunk graph. + // sessionStorage gates the auto-reload so an error we can't recover + // from (e.g. the new build is also missing the chunk) doesn't loop. + if (typeof window !== "undefined" && isChunkLoadError(error)) { + try { + const already = window.sessionStorage.getItem(CHUNK_RELOAD_KEY); + if (!already) { + window.sessionStorage.setItem(CHUNK_RELOAD_KEY, String(Date.now())); + window.location.reload(); + } + } catch { + // sessionStorage can throw under strict privacy modes — fall + // through to the error UI in that case. + } + } }, [error]); return ;