Skip to content

fix(router): end and log SSR failures after the response started in dev - #9293

Merged
maiieul merged 3 commits into
QwikDev:mainfrom
akasakariko:fix/9252-dev-ssr-error-response
Oct 25, 2026
Merged

maiieul merged 3 commits into
QwikDev:mainfrom
akasakariko:fix/9252-dev-ssr-error-response

Conversation

@akasakariko

@akasakariko akasakariko commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Closes #9252
Closes #9244

In dev, when a component throws during SSR and there is no <Catch> boundary, the request hangs forever and the error is never logged

Cause

runNext only finished the response on an error when !isDev In dev the error is left to the adapter, but once the response has started (the shell was already flushed) the middleware bails out on headersSent and nothing is written or logged

Fix

When the response has already started, handle dev like production: log the error and write the 500 error page before closing the stream

Production behavior is unchanged

Verification

  • new regression test fails on main (nothing written to the response) and passes with the fix
  • pnpm vitest run packages/qwik-router — 845 passed
  • pnpm tsc.check
  • eslint and prettier --check on the changed files
  • manual repro with a real HTTP socket: partial HTML followed by an uncaught throw now ends the response with the 500 page and logs the error instead of hanging

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where server-side rendering errors in development could leave a response unfinished after headers had been sent. The error is now logged and the response is completed, with the original error shown in the development error page. In production, the error page displays a generic “Internal Server Error” message without exposing the original error.

@akasakariko
akasakariko requested a review from a team as a code owner October 25, 2026 13:16
@changeset-bot

changeset-bot Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 15be63e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
@qwik.dev/router Patch
eslint-plugin-qwik Patch
@qwik.dev/mcp Patch
create-qwik Patch
@qwik.dev/devtools Patch
@qwik.dev/react Patch
@qwik.dev/utils Patch
@qwik.dev/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 86d5a64b-b70f-4052-b736-0362cde06900
Commits

Reviewing files that changed from the base of the PR and between d767f3f and f1a099b.

Files selected for processing: 2
  • packages/qwik-router/src/middleware/request-handler/user-response.ts
  • packages/qwik-router/src/middleware/request-handler/user-response.unit.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

When an SSR error occurs in development after response headers have been sent, runOnce logs the error and enters error-response handling. The development error response uses the original error, while the production response uses “Internal Server Error.” Tests check response output and writer closure.

Changes: SSR Error Handling

Layer / File(s) Summary
Development SSR error completion
packages/qwik-router/src/middleware/request-handler/user-response.ts, packages/qwik-router/src/middleware/request-handler/user-response.unit.ts, .changeset/dev-ssr-error-response.md
When headers have been sent, runOnce enters error-response handling. In development, it logs the error and uses the original error in the response. In production, it uses “Internal Server Error.” Tests check output, writer closure, and development logging. The changeset declares a patch release.

Priority: Normal

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

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

Possibly related PRs

  • QwikDev/qwik#9048: Both PRs handle uncaught SSR errors. This PR covers errors after headers are sent; #9048 covers middleware crashes before headers are sent.
  • QwikDev/qwik#9055: Both address failures during SSR. This PR finalizes errors that reach the request handler after the response starts; #9055 handles loader failures.
  • QwikDev/qwik#9050: Both involve request-handler error handling and ServerError.

Suggested reviewers: maiieul

Merge Risk: Minimal · up to f1a09

The development SSR error response can be merged after normal checks. The separate server-function stream issue remains outside this change.

Security architecture risk: Low · up to f1a09

The inspected change preserves HTML escaping and generic production error messages. No new security vulnerability was established. Remaining uncertainty concerns completion when a response stream is already locked or fails during writing or closing.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — The new diagnostic payload and original-error logging are gated on development mode and a response that has already started. Production continues to receive a generic error message. The inspected evidence does not establish which users or networks can reach deployed development servers.

Security Findings and Attack Paths

  • inferred — The routed error-message-to-HTML path does not establish an introduced injection vulnerability: the newly supplied development message still traverses the unchanged escaping formatter. Request influence over application error contents and deployment exposure were not demonstrated, so this conclusion is limited to the inspected path rather than a general safety guarantee.

Trust Boundaries and Controls

  • observed — The relevant boundary is application error data becoming browser-visible HTML and server-side diagnostics. The formatter encodes ampersands and angle brackets for its text slots, while the production branch substitutes a generic message. Already-committed headers are not rewritten.

Resilience and Maintainability Implications

  • inferred — The successful unlocked-stream path improves failure containment by ending responses that previously remained open in development. It does not provide a universal termination guarantee: adapter-level recovery after rejection and cleanup by an existing writer owner remain unverified. The added regression tests exercise the unlocked mocked-stream case.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: ending and logging SSR failures after the response starts in development.
Linked Issues check Passed Issue #9252 requires development SSR failures without a Catch boundary to be logged and to finish after the response starts. user-response.ts now enters the error path when requestEv.headersSent i…
Out of Scope Changes check Passed The changes stay within issue #9252. They update the router error path, add focused regression tests, and add a router changeset for the fix. No unrelated behavior or files are changed.
Full details: Linked Issues check

Explanation

Issue #9252 requires development SSR failures without a Catch boundary to be logged and to finish after the response starts. user-response.ts now enters the error path when requestEv.headersSent is true, logs the error in development, writes the development error page with the original error, and closes the writer. The new unit test verifies the error text, logging, and writer close. The production test verifies the generic error page remains unchanged.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@pkg-pr-new

pkg-pr-new Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@qwik.dev/core

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/core@9293

@qwik.dev/router

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/router@9293

@qwik.dev/utils

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/utils@9293

eslint-plugin-qwik

npm i https://pkg.pr.new/QwikDev/qwik/eslint-plugin-qwik@9293

create-qwik

npm i https://pkg.pr.new/QwikDev/qwik/create-qwik@9293

@qwik.dev/optimizer

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/optimizer@9293

@qwik.dev/devtools

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/devtools@9293

@qwik.dev/mcp

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/mcp@9293

commit: f1a099b

@maiieul
maiieul merged commit 155759e into QwikDev:main Oct 25, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants