renderRouterToStream returns a 200 for an aborted bot (isbot) SSR render
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
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 😢 ).
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 in packages/react-router/src/ssr/renderRouterToStream.tsx around the bot-specific wait, then run the linked minimal reproducer with pnpm install && pnpm dev and open /repro. Compare the abort behavior with the documented 1.170.8 and later versions; done means an aborted bot render no longer reports a successful 200 or empty 200 response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100