Skip to content

fix(router): reject server$ calls that get a non-server$ response - #9378

Merged
Varixo merged 1 commit into
QwikDev:mainfrom
thelastbackspace:fix/9335-server-fn-html-response
Nov 5, 2026
Merged

Varixo merged 1 commit into
QwikDev:mainfrom
thelastbackspace:fix/9335-server-fn-html-response

Conversation

@thelastbackspace

@thelastbackspace thelastbackspace commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

When a server$ request was answered with an HTML page (for example a middleware redirecting ?qfunc= requests to / on an expired session), the call resolved undefined. The client compared the whole Content-Type header, so text/html; charset=utf-8 matched none of the branches and the function just fell off the end. The same happened for application/json; charset=utf-8 and text/plain; charset=utf-8, which is what json() and text() in a request handler send.

Fix

  • Moved the response handling out of serverQrl into readServerFunctionResponse so it can be unit tested (in the vitest setup isServer is replaced at compile time, so I couldn't drive the client branch through server$ itself).
  • Compare only the media type (lowercased, parameters dropped).
  • Dropped text/html from the string branch. It's not in the Accept header the client sends, so it's never a server$ payload. Anything that doesn't match now throws an error with the status and content type, so the promise rejects.

Testing

  • pnpm vitest run packages/qwik-router/src/runtime/src/server-functions.unit.ts
  • New tests cover an HTML page (with and without charset) rejecting, and json/text with ; charset=utf-8 still resolving or throwing on 4xx. Both fail on main and pass with this change.

Fixes #9335

All qwik-router unit tests pass (885). The only failures in the full test.unit run here are the qwik-vite optimizer tests, which need the native optimizer binding I do not have built locally.

Summary by CodeRabbit

  • Bug Fixes
    • server$ calls now reject unexpected responses, such as HTML pages, instead of resolving to undefined.
    • Response content types are recognized consistently, including when they use different capitalization or include parameters.
    • Error responses preserve their response body as the rejection value. JSON and plain-text responses continue to be handled according to their status.

server$ compared the whole Content-Type header, so 'text/html; charset=utf-8'
(e.g. a page after a middleware redirect) matched no branch and the call
resolved undefined. Compare only the media type and throw for anything
that is not a server$ payload.

Fixes QwikDev#9335
@thelastbackspace
thelastbackspace requested a review from a team as a code owner November 5, 2026 02:33
@changeset-bot

changeset-bot Bot commented Nov 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c12cf1c

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 Nov 5, 2026 •

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

serverQrl delegates client response handling to readServerFunctionResponse. The helper parses supported response types and rejects unsupported types, including HTML. Unit tests cover media type parameters, case-insensitive matching, and error responses.

Changes: Server function response handling

Layer / File(s) Summary
Response parsing and validation
packages/qwik-router/src/runtime/src/server-functions.ts, packages/qwik-router/src/runtime/src/server-functions.unit.ts, .changeset/server-fn-html-response.md
serverQrl delegates response handling to readServerFunctionResponse. The helper parses supported content types without parameters and matches them case-insensitively. Unsupported types, including HTML, produce an unexpected-response error. Tests cover these cases and status-based errors. The changeset records the fix.

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

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: varixo

Merge Risk: Minimal · up to c12cf

The change rejects unsupported responses while preserving supported JSON and text handling. No actionable merge-blocking risk is established; merge after normal checks pass.

Pre-merge checks: Passed 5

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the main change: server$ calls now reject when they receive a non-server$ response, such as an HTML page. The changeset, the new readServerFunctionResponse helper, and its tests all ma…
Linked Issues check Passed [#9335] Requirement: a server$ call must reject when the response is an HTML page, not resolve undefined. At head, serverQrl returns readServerFunctionResponse(res, abortSignal) (server-functions.ts).…
Out of Scope Changes check Passed All changes relate to #9335. The server-functions.ts diff moves the existing response-handling logic into readServerFunctionResponse. The qwik-json-stream, qwik-json, and application/json branches kee…
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Full details: Title check

Explanation

The title names the main change: server$ calls now reject when they receive a non-server$ response, such as an HTML page. The changeset, the new readServerFunctionResponse helper, and its tests all match this change. The title follows the conventional commit format and is specific enough for a teammate scanning history.

Full details: Linked Issues check

Explanation

[#9335] Requirement: a server$ call must reject when the response is an HTML page, not resolve undefined. At head, serverQrl returns readServerFunctionResponse(res, abortSignal) (server-functions.ts). That helper strips parameters from Content-Type (split on ';', trim, lowercase) before matching. The text/html branch was removed. Any unmatched media type, including text/html with or without charset, now throws Error('server$ got an unexpected response: <status> <content-type>'). The returned promise therefore rejects, as the issue expects. Charset-bearing application/json and text/plain responses still resolve or throw as before. The unit tests in server-functions.unit.ts cover the HTML rejection, charset handling, a 401 text/plain rejection value, and the Application/JSON casing. The tests call readServerFunctionResponse directly, not through server$ end to end. This is adequate because serverQrl returns that promise unchanged. I did not run the tests. The result relies on the reported test run and on reading the code. The client Accept header at head is 'application/json, application/qwik-json, text/qwik-json-stream, text/plain', so removing text/html from the string branch does not drop a payload type that the client requests.

Full details: Out of Scope Changes check

Explanation

All changes relate to #9335. The server-functions.ts diff moves the existing response-handling logic into readServerFunctionResponse. The qwik-json-stream, qwik-json, and application/json branches keep their original logic. The only behavior changes are the media-type normalization, the removal of text/html from the string branch, and the new error for unmatched types. These changes implement the issue. The unit test diff tests the new helper. The changeset file adds a patch note for @qwik.dev/router describing the fix. The helper export is marked @internal and exists only for tests. No unrelated code changes appear in the reviewed diff.

Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 2 functions across 2 files. (1 skipped: 1 unsupported.)

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

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: 2101f96b-02d2-45d7-8af7-7aafa2c859f4
Commits

Reviewing files that changed from the base of the PR and between ebb8a5c and c12cf1c.

Files selected for processing: 3

  • .changeset/server-fn-html-response.md
  • packages/qwik-router/src/runtime/src/server-functions.ts
  • packages/qwik-router/src/runtime/src/server-functions.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.

@pkg-pr-new

pkg-pr-new Bot commented Nov 5, 2026

Copy link
Copy Markdown

Open in StackBlitz

@qwik.dev/core

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

@qwik.dev/router

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

@qwik.dev/utils

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

eslint-plugin-qwik

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

create-qwik

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

@qwik.dev/optimizer

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

@qwik.dev/devtools

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

@qwik.dev/mcp

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

commit: c12cf1c

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

⚡ Docs preview for c12cf1c

@Varixo Varixo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks for the PR, lgtm

@Varixo
Varixo merged commit 1351e1a into QwikDev:main Nov 5, 2026
106 of 108 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

Development

Successfully merging this pull request may close these issues.

[🐞] server$ resolves undefined when the response is an HTML page

2 participants