[Start] Client abort mid-SSR kills `vite dev` 120s later with @tanstack/nitro-v2-vite-plugin (unhandled 'error' from the stream-lifetime watchdog)
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
With @tanstack/nitro-v2-vite-plugin on Vite 6, a client that aborts a request while SSR is still streaming leaves router-core's SSR transform stream uncleaned: the abort never propagates to the transform's cleanup, so serialization never finishes. 120 seconds later the stream-lifetime watchdog in transformStreamWithRouter calls controller.error(...) — but by then the adapting node Readable has no consumer and no 'error' listener, so the entire dev process exits with an unhandled 'error' event:
SSR stream transform exceeded maximum lifetime (120000ms), forcing cleanup
node:events:485
throw er; // Unhandled 'error' event
^
Error: Stream lifetime exceeded
at Timeout.<anonymous> (.../@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:478:32)
Emitted 'error' event on Readable instance at:
at emitErrorNT (node:internal/streams/destroy:170:8)
error: script "dev" exited with code 1
This bites constantly in real usage: defaultPreload: "intent" aborts hover preloads all the time, so on any app with slow-ish SSR the dev server dies ~2 minutes after ordinary navigation.
What I've isolated:
- A fresh
create-start-appscaffold (Vite 8 + the newnitro/viteplugin, router-core 1.171.14) does not reproduce — the abort propagates, the transform is cleaned up immediately, and the watchdog never fires. - The watchdog code in
transformStreamWithRouteris identical between router-core 1.171.13 and 1.171.14, so the difference is the dev-server adapter chain: the abort→cleanup propagation hole is specific to the@tanstack/nitro-v2-vite-pluginpipeline. - The production build (
node .output/server/index.mjs, node-server preset) tolerates the same error — this is dev-only.
Two possible fixes, not mutually exclusive: propagate request aborts to the transform-stream cleanup in the nitro-v2 dev pipeline, and/or harden the watchdog in router-core to not error() a stream that no longer has a consumer (which would contain the blast radius for any adapter that misses cancellation).
Complete minimal reproducer
https://github.com/jayscambler/tanstack-start-ssr-abort-repro
(Three tiny routes; /slow has a 3s loader so a curl abort reliably lands mid-SSR.)
Steps to Reproduce the Bug
bun install && bun run dev(vite dev, port 3100)curl -s --max-time 0.5 http://localhost:3100/slow— aborts while the 3s loader is still running- Wait ~150 seconds
curl http://localhost:3100/— the dev process has exited with code 1 (crash above in the terminal)
Expected behavior
An aborted request cleans up its SSR transform stream (as the Vite 8 + nitro/vite pipeline does), and in no case should a watchdog firing on an abandoned stream take down the whole dev server.
Screenshots or Videos
No response
Platform
- OS: macOS 15 (also observed on the bun preset)
- @tanstack/react-start: 1.168.26
- @tanstack/react-router: 1.170.16
- @tanstack/router-core: 1.171.13 (watchdog identical in 1.171.14)
- @tanstack/nitro-v2-vite-plugin: 1.155.0
- vite: 6.3.5, node: 23.11.0
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 with the minimal reproducer and the transformStreamWithRouter watchdog, then trace request-abort handling through the @tanstack/nitro-v2-vite-plugin dev adapter and its adapting Node Readable. Reproduce with the provided bun commands and compare the failing Vite 6 pipeline with the working Vite 8 nitro/vite pipeline. Done means an aborted SSR request cleans up without a later watchdog crash or dev-server exit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript, vite
- Domain
- backend, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100