Skip to content

fix(router): restore .fail() behavior#8756

Merged
wmertens merged 1 commit into
build/v2from
v2-loaders-fixup
Jun 21, 2026
Merged

fix(router): restore .fail() behavior#8756
wmertens merged 1 commit into
build/v2from
v2-loaders-fixup

Conversation

@wmertens

Copy link
Copy Markdown
Member

For backwards compatibility

This is the previous behavior for backwards compatibility
@wmertens wmertens requested review from a team as code owners June 21, 2026 08:46
Copilot AI review requested due to automatic review settings June 21, 2026 08:46
@wmertens wmertens enabled auto-merge June 21, 2026 08:46
@changeset-bot

changeset-bot Bot commented Jun 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 108fb66

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

This PR includes changesets to release 5 packages
Name Type
@qwik.dev/router Patch
eslint-plugin-qwik Patch
@qwik.dev/core Patch
create-qwik Patch
@qwik.dev/react 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

@pkg-pr-new

pkg-pr-new Bot commented Jun 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

@qwik.dev/core

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

@qwik.dev/router

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

eslint-plugin-qwik

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

create-qwik

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

@qwik.dev/optimizer

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

commit: 108fb66

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Restores Qwik Router routeLoader$().fail() backward-compatible behavior by treating fail() results as plain loader data instead of routing them through the loader JSON error envelope.

Changes:

  • Updated getRouteLoaderResponse() to always return fail() results in the d (data) channel and reserve e for thrown ServerErrors.
  • Adjusted loader JSON caching logic to treat fail() responses as non-cacheable.
  • Updated docs and added unit coverage for the loader response envelope behavior; added a router changeset.

Focused security / trust-boundary check

  • Boundary changed: loader JSON response shaping ({ d, r, e }) and caching decisions in the request handler.
  • Guard/invariant: redirects/errors are still represented via r/e (with thrown ServerErrors only), and loader execution remains wrapped by getRouteLoaderResponse()/jsonRequestWrapper() to prevent raw errors from leaking into SPA navigation.
  • Coverage: added unit tests around getRouteLoaderResponse() envelope behavior; loader-handler caching behavior should be covered by an additional handler unit test.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/qwik-router/src/runtime/src/route-loaders.unit.ts Adds unit tests asserting fail() stays in d and thrown ServerError maps to e.
packages/qwik-router/src/runtime/src/route-loaders.ts Changes loader JSON envelope behavior so fail() is treated as plain data; updates type docs.
packages/qwik-router/src/middleware/request-handler/handlers/loader-handler.ts Updates caching decision logic to avoid caching fail() results.
packages/docs/src/routes/docs/(qwikrouter)/route-loader/index.mdx Updates docs to explain inline fail() vs thrown error() behavior.
.changeset/loader-fail-value.md Adds a patch changeset documenting the restored fail() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +95 to +98
// Only successful data envelopes are cacheable; never cache redirects, errors, or fail() results.
const failed =
responseData.d && typeof responseData.d === 'object' && (responseData.d as any).failed;
const cacheable = cacheKey && !responseData.r && !responseData.e && !failed;
Comment on lines +97 to +98
- **`throw requestEvent.error(status, data)`** — throw a `ServerError` directly. `signal.error` is `ServerError {status, data}`. Reading `signal.value` re-throws the error, so you should branch on `signal.error` first. This is the recommended way to signal failure from a loader.
- **`return requestEvent.fail(status, data)`** — returns an inline failure. `signal.value.failed` is `true` and `signal.value` contains the rest of the data.
- **`throw requestEvent.error(status, data)`** — throw a `ServerError` directly. `signal.error` is `ServerError {status, data}`. Reading `signal.value` re-throws the error, so you should branch on `signal.error` first. This is the recommended way to signal failure from a loader.
- **`return requestEvent.fail(status, data)`** — returns an inline failure. `signal.value.failed` is `true` and `signal.value` contains the rest of the data.

In both cases, the HTTP response status is set to `status`, and the result is not cacheable.
@wmertens wmertens merged commit 68d81bb into build/v2 Jun 21, 2026
50 checks passed
@wmertens wmertens deleted the v2-loaders-fixup branch June 21, 2026 08:54
@github-project-automation github-project-automation Bot moved this from Waiting For Review to Done in Qwik Development Jun 21, 2026
@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor
built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
qwik-docs ✅ Ready (View Log) Visit Preview 108fb66

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants