Which project does this relate to?
Start
Describe the bug
A recent change to renderRouterToStream (see below), means when request.signal aborts, we now get a status of 200 instead of an error. This change was introduced in v1.170.9 (PR #7497).
// 1.170.8 (before)
if (isbot(request.headers.get('User-Agent'))) {
await stream.allReady
}
// 1.170.9 → 1.170.18 (after)
if (isbot(request.headers.get('User-Agent'))) {
await waitForReadyOrAbort(stream.allReady, request.signal)
}
Complete minimal reproducer
https://github.com/roduyemi/tanstack-start-ssr-bot-abort-200
Steps to Reproduce the Bug
- Clone the repo and run
pnpm install && pnpm dev.
- Open http://localhost:3000/repro.
/repro does a server side render of /slow (a route that suspends) with a Googlebot user-agent, then aborts the request about 100ms in (while it's still waiting on the bot's allReady).
- See a render that was aborted before it finished has a status of 200.
{ "status": 200, "hasTitle": true, "hasSlowRouteContent": false }
Expected behavior
An aborted bot render should surface as an error (e.g. 5xx) - or a status other than 200 (success). This was the behaviour before 1.170.10, when await stream.allReady rejected on abort.
Screenshots or Videos
No response
Platform
- Router / Start Version: @tanstack/react-router 1.170.18, @tanstack/react-start 1.168.33
- OS: macOS
- Browser: N/A — server-side SSR bug, reproduced via curl with a Googlebot UA (any browser)
- Browser Version: N/A
- Bundler: Vite 8
- Bundler Version: 8.2.0
Additional context
It's worse on workerd in production. When the abort races the client read, stream.cancel() often discards the buffered shell before it's flushed, so we end up serving the crawler a completely empty, 0 byte 200, which then gets indexed (not great for SEO 😢 ).
Which project does this relate to?
Start
Describe the bug
A recent change to renderRouterToStream (see below), means when request.signal aborts, we now get a status of 200 instead of an error. This change was introduced in v1.170.9 (PR #7497).
Complete minimal reproducer
https://github.com/roduyemi/tanstack-start-ssr-bot-abort-200
Steps to Reproduce the Bug
pnpm install && pnpm dev./repro does a server side render of /slow (a route that suspends) with a Googlebot user-agent, then aborts the request about 100ms in (while it's still waiting on the bot's allReady).
Expected behavior
An aborted bot render should surface as an error (e.g. 5xx) - or a status other than 200 (success). This was the behaviour before 1.170.10, when await stream.allReady rejected on abort.
Screenshots or Videos
No response
Platform
Additional context
It's worse on workerd in production. When the abort races the client read, stream.cancel() often discards the buffered shell before it's flushed, so we end up serving the crawler a completely empty, 0 byte 200, which then gets indexed (not great for SEO 😢 ).