Skip to content

fix(router-core): close instead of error stream on lifetime watchdog expiry - #7909

Open
Brumor wants to merge 1 commit into
TanStack:mainfrom
Brumor:fix/ssr-stream-lifetime-watchdog
Open

fix(router-core): close instead of error stream on lifetime watchdog expiry#7909
Brumor wants to merge 1 commit into
TanStack:mainfrom
Brumor:fix/ssr-stream-lifetime-watchdog

Conversation

@Brumor

@Brumor Brumor commented Jul 27, 2026

Copy link
Copy Markdown

Fixes #7748

#7748 has a nice minimal repro and isolates this to two layers: the Nitro V2 dev adapter misses a client abort, then router-core turns the abandoned stream into an unhandled error when the lifetime watchdog fires two minutes later. This PR fixes the router-core half, so a missed cancellation cannot take down the server runtime.

Basically: the watchdog is a leak-prevention fallback. By the time it fires, there is no useful consumer left to receive the error.

This changes both router-core stream paths to close cleanly when the lifetime watchdog fires. The existing warning and cleanup reason stay in place, so the upstream app render is still cancelled and the SSR resources are released. Real render and serialization failures still error the stream.

Added coverage for the fast and main paths, both with and without an active reader.

Tests:

  • affected lint
  • affected type tests
  • affected unit tests

Summary by CodeRabbit

  • Bug Fixes

    • SSR streams now close cleanly when their lifetime expires, preventing unnecessary stream errors.
    • Stream cleanup and upstream cancellation continue to run reliably across supported streaming modes.
    • Active readers now finish gracefully when a stream reaches its lifetime limit.
  • Tests

    • Expanded coverage for stream timeout behavior, including fast-path and standard streaming scenarios.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The SSR transform lifetime watchdog now closes timed-out streams instead of erroring them. Tests cover both fast and main paths with and without active readers, and a patch changeset documents the release.

Changes

SSR stream timeout handling

Layer / File(s) Summary
Close timed-out streams and validate teardown
packages/router-core/src/ssr/transformStreamWithRouter.ts, packages/router-core/tests/transformStreamWithRouter.test.ts, .changeset/calm-streams-close.md
Both timeout handlers call safeClose() before cleanup. Parameterized tests verify cancellation, warning emission, single cleanup, and resolution of active readers across both stream paths. A patch changeset records the behavior change.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: schiller-manuel

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: closing SSR streams on watchdog expiry instead of erroring them.
Linked Issues check ✅ Passed The watchdog now closes abandoned SSR streams without error while preserving cleanup and cancellation, matching #7748's main objective.
Out of Scope Changes check ✅ Passed The changes are limited to the watchdog fix, tests, and a changeset; no unrelated scope is evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Brumor
Brumor marked this pull request as ready for review July 27, 2026 15:35

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/router-core/tests/transformStreamWithRouter.test.ts`:
- Around line 679-680: Remove the any casts from the router and stream arguments
in the watchdog test around the transform invocation. Update the test fixtures
and their declarations to satisfy the required router and upstream stream
contracts directly, preserving the existing behavior while allowing TypeScript
strict checking to catch API incompatibilities.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 730e3f39-0ccd-47fd-8e08-525ae3c6c986

📥 Commits

Reviewing files that changed from the base of the PR and between 179d9b9 and 2d51dfe.

📒 Files selected for processing (3)
  • .changeset/calm-streams-close.md
  • packages/router-core/src/ssr/transformStreamWithRouter.ts
  • packages/router-core/tests/transformStreamWithRouter.test.ts

Comment thread packages/router-core/tests/transformStreamWithRouter.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Start] Client abort mid-SSR kills vite dev 120s later with @tanstack/nitro-v2-vite-plugin (unhandled 'error' from the stream-lifetime watchdog)

1 participant