router-core@1.171.7+: SSR query stream never closes with ssr-query → "Serialization timeout after app render finished"
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
Bug
router-core@1.171.7+ regresses SSR streaming when used with @tanstack/react-router-ssr-query: the dehydration query stream is never closed, so the response stream hangs until the 60s serialization timeout fires ("Serialization timeout after app render finished"). Real browsers paint early; curl/bots see the full ~30–60s hang.
Root cause
PR #7497 ("fix streaming", landed in router-core@1.171.7) added a reserveStreamFastPath() fast path and guarded onRenderFinished:
// router-core 1.171.6 (works):
onRenderFinished: (listener) => renderFinishedListeners.push(listener),
// router-core 1.171.7+ (regressed):
reserveStreamFastPath() {
if (!cleanupStarted && _serializationFinished && !streamFastPathReserved
&& renderFinishedListeners.length === 0 && !injectedHtmlBuffer && !scriptBuffer.hasPending()) {
streamFastPathReserved = true;
return true;
}
return false;
},
onRenderFinished: (listener) => {
if (cleanupStarted || streamFastPathReserved) return; // ← silently drops the listener
renderFinishedListeners.push(listener);
},
@tanstack/router-ssr-query-core@1.169.1 registers the query-stream close via onRenderFinished:
// router-ssr-query-core 1.169.1, setupCoreRouterSsrQueryIntegration
router.serverSsr.onRenderFinished(() => {
if (!queryStream.isClosed()) queryStream.close();
...
});
When reserveStreamFastPath() has already set streamFastPathReserved = true by the time the integration registers its onRenderFinished listener, that listener is silently dropped. queryStream is therefore never closed → serializationFinished never becomes true → transformStreamWithRouter hits the serialization timeout.
Versions
- Broken:
@tanstack/react-router@1.170.x(→router-core@1.171.7–1.171.9) +@tanstack/react-router-ssr-query@1.167.1(→router-ssr-query-core@1.169.1) - Works:
@tanstack/react-router@1.169.0(→router-core@1.169.0), orrouter-core@1.171.6(pre-#7497, no guard)
Confirmed onRenderFinished is unguarded in 1.171.6 and guarded in 1.171.7, 1.171.8, 1.171.9.
Reproduction
React SSR with streaming (renderToReadableStream + transformReadableStreamWithRouter) and setupRouterSsrQueryIntegration, where a route loader uses ensureQueryData/prefetchQuery so there are dehydrated queries. On a route that resolves all queries quickly, reserveStreamFastPath() fires before the ssr-query integration registers its close listener → the stream hangs.
Expected
The latest published @tanstack/react-router-ssr-query is 1.167.1, which does not appear to account for reserveStreamFastPath, so there is currently no version combination on router-core@1.171.7+ that closes the query stream. Either:
onRenderFinishedshould still register (or immediately invoke) the listener when the fast path is already reserved, or- ship a
router-ssr-query-corerelease coordinated with thereserveStreamFastPathchange.
Happy to provide a minimal repro repo if useful.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing reserveStreamFastPath and onRenderFinished in router-core, then inspect setupRouterSsrQueryIntegration and its queryStream close listener in router-ssr-query-core. Reproduce with renderToReadableStream, transformReadableStreamWithRouter, and a loader using ensureQueryData or prefetchQuery; done means the dehydrated query stream closes and the response does not hit the serialization timeout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100