ssr:false: redirect thrown in a child beforeLoad during the initial load blanks the app (MatchInner throws `undefined`), reproducer for #7910
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 48/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- react, typescript
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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.
- Ngôn ngữ chính
- TypeScript
- Star
- 15.2k
- Fork
- 1.9k
- Merge trung bình
- 1 ngày 8 giờ
- Pull request đã merge (30 ngày)
- 70
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của TanStack/router
-
router.startViewTransition leaves the ready/finished promises unhandled, so a skipped transition throws an unhandled AbortErrorCó thể đã có người làm @unjica đã nhận 4 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
TanStack/router#8776 · 3 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Router devtools crash when search params contain a BigInt (JSON.stringify in history tracking)Có thể đã có người làm @A-Raphie đã nhận 8 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
-
docs: `createLink` has no API reference page; 3 how-to guides link to a missing `#createlink` anchorCó thể đã có người làm @A-Raphie đã nhận 8 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Inline scripts are duplicated after hydration when the CSP nonce is sent in a headerCó thể đã có người làm @gabriel-le đã nhận 29 ngày trước. Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
Maintainer thường phản hồi trong vòng 1 ngày
-
start-plugin-core: sitemap lastmod and pages.json lastBuilt are stamped with the build's wall clock (no SOURCE_DATE_EPOCH support)Có thể đã có người làm @treadnot đã nhận 30 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của TanStack/router
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 Dưới một giờ Mức phù hợp với người mới 80/100
nuxt-content/nuxt-studio#599 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 79/100
hurttlocker/o8#4997 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
danielmiessler/LifeOS#2413 ·
Maintainer thường phản hồi trong vòng 3 ngày
-
Plugin: sheet music can't be scrolled by hand before playbackCó thể đã có người làm @snakajima đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
receptron/jinglescript#51 ·
Maintainer thường phản hồi trong vòng 1 ngày