TanStack / TanStack/router

renderRouterToStream returns a 200 for an aborted bot (isbot) SSR render

Open
#7,929 0 comments 1 reaction 0 assignees View on GitHub

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
  1. Clone the repo and run
pnpm install && pnpm dev.
  1. 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).
  2. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.