ssr:false: redirect thrown in a child beforeLoad during the initial load blanks the app (MatchInner throws `undefined`), reproducer for #7910
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 48/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- react, typescript
Línea de trabajo
Start by tracing hydration and the redirected load through MatchInnerImpl, getMatchPromise, CatchBoundary, and loadRouteMatch; the issue gives a reproducible timing scenario but no test file or code locations. Reproduce with the supplied ssr: false parent and child beforeLoad redirect, adding router.invalidate() during the redirected load. Done means the initial page no longer blanks and the redirect reaches the destination reliably.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Versions:
- @tanstack/react-router 1.170.18
- @tanstack/router-core 1.171.15
- @tanstack/react-start 1.167.x (start-client-core 1.170.14)
- React 19.2
- Vite 8.1, dev mode
Describe the bug
A full page load of a URL under an ssr: false layout, where a child route's async beforeLoad throws redirect(), can leave the page blank. The console shows Uncaught undefined and "An error occurred in the component".
Navigating to the same URL client-side works.
This is the issue reported in #7910, which was closed for lack of a reproducer. Here is one with no .preload() forwarding.
Minimal reproduction
// routes/zzrepro.tsx
export const Route = createFileRoute("/zzrepro")({
ssr: false,
beforeLoad: async () => { await wait(200); return { user: { id: "x" } } },
component: () => <Outlet />,
})
// routes/zzrepro.a.tsx
export const Route = createFileRoute("/zzrepro/a")({
beforeLoad: async () => { await wait(200); throw redirect({ to: "/zzrepro/b" }) },
component: () => <div>A</div>,
})
// routes/zzrepro.b.tsx
export const Route = createFileRoute("/zzrepro/b")({
beforeLoad: async () => { await wait(200) },
component: () => <div>B rendered OK</div>,
})
In our app, the redirect alone was enough to blank the page.
In this synthetic version it reproduces deterministically if router.invalidate() is also called while the redirected load is in flight, about 500–900 ms after page load.
For example, Supabase's onAuthStateChange emits SIGNED_IN on every page load. A root-level listener that calls router.invalidate() on it hits this window.
Analysis
- The
ssr: falsematch is dehydrated aspending. On the client,hydrate()puts it in the active matches, androuter.load()runs the guards. - The child throws a redirect.
navigate({ replace: true })starts a new load whose pending matches reuse the same id for thessr: falselayout. They share_nonReactive. - That load finishes the layout match.
loadRouteMatchresolves and clears_nonReactive.loadPromise. This happens beforeonReadycommits the pending matches. - React renders the still-active stale snapshot (
status: "pending").MatchInnerImpldoesthrow getMatchPromise(match, "loadPromise"), which isundefined. CatchBoundarystoresundefinedas the error. That is falsy, so it re-renders its children, which throw again. React gives up and unmounts the root.- The router state afterwards is correct (all matches
success), but nothing is mounted.router.state.statusstayspendingforever.
Workaround we ship (patch-package)
In MatchInnerImpl's getMatchPromise:
return router.getMatch(match.id)?._nonReactive[key]
?? match._nonReactive[key]
?? router.latestLoadPromise
?? new Promise((resolve) => setTimeout(resolve, 0))
Suggested fixes
- Never throw a non-thenable from the pending branches.
- Or keep
loadPromisealive until the pending matches are committed. - Separately,
CatchBoundarycould treat a thrownundefinedas an error, so it renders theerrorComponentinstead of looping.
- Lenguaje dominante
- TypeScript
- Estrellas
- 15.2k
- Forks
- 1.9k
- Merge medio
- 1 d 13 h
- PR fusionados (30 d)
- 76
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
-
router.startViewTransition leaves the ready/finished promises unhandled, so a skipped transition throws an unhandled AbortErrorPosiblemente ocupada @unjica la tomó hace 2 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
TanStack/router#8776 · 3 comentarios · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Router devtools crash when search params contain a BigInt (JSON.stringify in history tracking)Posiblemente ocupada @A-Raphie la tomó hace 6 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 1 día
-
docs: `createLink` has no API reference page; 3 how-to guides link to a missing `#createlink` anchorPosiblemente ocupada @A-Raphie la tomó hace 6 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
Los mantenedores suelen responder en 1 día
-
Inline scripts are duplicated after hydration when the CSP nonce is sent in a headerPosiblemente ocupada @gabriel-le la tomó hace 27 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 28 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día
Todos los issues de TanStack/router
Issues similares
-
type: bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 79/100
Los mantenedores suelen responder en 1 día
-
0️⃣ phase/new
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 70/100
microsoft/playwright#43640 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100