lazyRouteComponent reload guard key collides on Safari, capping stale-deploy recovery at one per tab
Los mantenedores suelen responder en 1 día
@mithatakbulut ya está trabajando en esto.
Desde el 16/9/2026.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 76/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- react, typescript
Línea de trabajo
Comienza en packages/react-router/src/lazyRouteComponent.tsx, donde se ensambla la protección de sessionStorage, y sigue el sitio de llamada de lazyRouteComponent para confirmar el route id disponible. Conserva la protección de recarga de una sola vez para la misma ruta, a la vez que permites que los fallos independientes de Safari en lazy routes se recuperen por separado; verifica el comportamiento con dos lazy routes y fallos sucesivos de despliegues obsoletos.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Which project does this relate to?
Router
Describe the bug
lazyRouteComponent's stale-deploy recovery guards its one-time reload with a sessionStorage key derived solely from the error message:
https://github.com/TanStack/router/blob/main/packages/react-router/src/lazyRouteComponent.tsx
const storageKey = `tanstack_router_reload:${error.message}`
if (!sessionStorage.getItem(storageKey)) {
sessionStorage.setItem(storageKey, '1')
window.location.reload()
throw new Promise(() => {})
}
That works when the message identifies the chunk, which it does on Chrome and Firefox — both append the module URL. It does not on Safari, whose message is the bare string Importing a module script failed. with no URL. isModuleNotFoundError's own comments record this difference:
// chrome: "Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
// firefox: "error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
// safari: "Importing a module script failed."
So on Safari the key collapses to a single value — tanstack_router_reload:Importing a module script failed. — shared by every lazy route in the application, for the lifetime of the tab.
The consequence is that a Safari tab gets one recovery, ever, no matter how many separate chunks fail or how many deploys it lives through. The first stale chunk reloads and recovers; every subsequent one finds the key already set, skips the reload, and rethrows — leaving the user on the error component with no automatic recovery, which is the exact situation the guard exists to prevent.
Chrome and Firefox are unaffected: each chunk URL yields its own key, so the guard does what it is meant to do (suppress a reload loop for one chunk that stays missing, while still recovering other chunks).
Note this is distinct from #7633. That issue is about isModuleNotFoundError failing to classify certain failures; this is about the guard key being non-unique once a failure has been correctly classified. Widening the predicate does not address it, and #7653 (now closed) would not have.
Complete minimal reproducer
No hosted reproducer — this is reasoned from the source above rather than from a running app, because reproducing it needs two successive deploys against one long-lived Safari tab. The conditions are exact and the code path is short, so I hope the inspection is enough to act on; happy to build a reproducer if that is the blocker.
The observable prerequisite (Safari's message carrying no URL) is already asserted by the router's own source comments, quoted above.
Steps to Reproduce the Bug
- Build and deploy an app with at least two code-split routes,
/aand/b, whose chunks are content-hashed. - Open the app in Safari and stay on the home route without refreshing.
- Deploy a change that rehashes the chunks for both
/aand/b. The old chunks are no longer served. - Navigate to
/a. The import fails,isModuleNotFoundErrormatches, the guard key is set, and the tab reloads — recovered, as designed. - With that tab still open, deploy a second change that rehashes the chunks again.
- Navigate to
/b(or back to/a).
Expected behavior
Step 6 performs one reload and recovers, the same as step 4 did — the guard should suppress a repeated reload for the same failing chunk, not for every chunk in the app.
Actual behavior
Step 6 performs no reload. sessionStorage already holds tanstack_router_reload:Importing a module script failed. from step 4, so the guard declines and the error is rethrown to the error component. The user is stuck until they refresh by hand.
Platform
- Browser: Safari (any version; the behavior follows from Safari's error message wording)
- Affected packages:
@tanstack/react-router(guard),@tanstack/router-core(message classification) - Versions: reproduces on current
latest—@tanstack/[email protected],@tanstack/[email protected]
Additional context
A fix would be to key the guard on something that identifies the chunk rather than on the message alone — the route id available at the lazyRouteComponent call site is the obvious candidate, since it is stable across deploys and unique per split route:
const storageKey = `tanstack_router_reload:${routeId}:${error.message}`
That preserves the existing loop protection (the same route failing twice in one tab still only reloads once) while letting a different route recover on its own.
Found while tracking down why a stale tab was not recovering after a deploy on a TanStack Start app. The server-side half of that turned out to be ours to fix, but this guard caps how well the built-in recovery can work on Safari regardless.
- Lenguaje dominante
- TypeScript
- Estrellas
- 15.2k
- Forks
- 1.9k
- Merge medio
- 1 d 12 h
- PR fusionados (30 d)
- 106
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de TanStack/router
-
Inline scripts are duplicated after hydration when the CSP nonce is sent in a headerPosiblemente ocupada @gabriel-le la tomó hace 13 días. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
Los mantenedores suelen responder en 1 día
-
start-plugin-core: sitemap lastmod and pages.json lastBuilt are stamped with the build's wall clock (no SOURCE_DATE_EPOCH support)Posiblemente ocupada @treadnot la tomó hace 14 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día
-
Empty .ts route file is scaffolded with JSX, breaking all route generationPosiblemente ocupada @nathan-logan la tomó hace 18 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
information needed
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
TanStack/router#8464 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
start-compiler-plugin fails to lazy-load dependencies with Vite bundledDevPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
TanStack/router#8407 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 1 día
Todos los issues de TanStack/router
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 72/100
cline/mcp-marketplace#2932 ·
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
lingdojo/kana-dojo#32188 · 1 comentario · 5 reacciones ·
Los mantenedores suelen responder en 1 día
-
triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Portkey-AI/gateway#1844 ·
Los mantenedores suelen responder en 1 día
-
needs triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 61/100
rjsf-team/react-jsonschema-form#5495 ·
Los mantenedores suelen responder en 2 días