Skip to content

feat(qwik-router): error channel — return error() → .error, deprecate fail()/value.failed#8738

Open
maiieul wants to merge 12 commits into
QwikDev:build/v2from
maiieul:v2-action-async-signal
Open

feat(qwik-router): error channel — return error() → .error, deprecate fail()/value.failed#8738
maiieul wants to merge 12 commits into
QwikDev:build/v2from
maiieul:v2-action-async-signal

Conversation

@maiieul

@maiieul maiieul commented Jun 14, 2026

Copy link
Copy Markdown
Member

What is it?

  • Feature / enhancement

Description

Non-breaking minor. return error(status, data) surfaces an inline, typed ServerError on loader.error / action.error; return fail() and .value.failed are deprecated but still work; throw error() keeps aborting to the global error page. Validator failures populate both channels (typed .error + deprecated value.failed). Underpinned by a core change: AsyncSignal.value no longer throws on error state by default (read .error instead) — a throwOnError opt-in will follow in a later minor via RFC.

Brings actions to the same AsyncSignal surface loaders already have: adds action.loading and action.promise(); isRunning is deprecated in favor of loading (still works). .value/.error unchanged.

@maiieul maiieul requested review from a team as code owners June 14, 2026 15:26
@changeset-bot

changeset-bot Bot commented Jun 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a228b2a

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/core Minor
eslint-plugin-qwik Minor
@qwik.dev/router Minor
@qwik.dev/react Minor
create-qwik Minor

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

@maiieul maiieul self-assigned this Jun 14, 2026
@maiieul maiieul moved this to Waiting For Review in Qwik Development Jun 14, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@qwik.dev/core

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

@qwik.dev/router

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

eslint-plugin-qwik

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

create-qwik

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

@qwik.dev/optimizer

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

commit: a228b2a

@github-actions

github-actions Bot commented Jun 14, 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 a228b2a

@maiieul maiieul changed the title feat(qwik-router): actions expose the AsyncSignal surface (loading, promise) feat(qwik-router): error channel — return error() → .error, deprecate fail()/value.failed Jun 14, 2026
maiieul added 7 commits June 15, 2026 14:06
…ault

Reading .value in an error state returns the stale/initial value instead
of re-throwing; the error stays available via .error/.untrackedError. The
throw path is preserved behind an internal THROW_ON_ERROR flag (unexposed)
for a future throwOnError option.
return error(status, data) now surfaces a typed ServerError on
loader.error / action.error (typed ValidatorErrorType for zod$/valibot$/validator$).
return fail() and the .value.failed branch are deprecated but keep working.
throw error() still aborts to the error page. Validator failures populate
both channels for back-compat.
…omise)

Actions now mirror the loader AsyncSignal shape: add reactive `loading` and a
`promise()` that resolves when the in-flight submission settles. `isRunning` is
kept as a deprecated alias of `loading`. Non-breaking minor.
…r channel

- route-loader 'Signaling failure': describe the real model (return error() →
  .error; return fail() → .value.failed deprecated; throw error() → abort), was
  describing the old both-to-.error design
- action success render gated on !action.error (action.value holds the deprecated
  fail-union on validator failures, so a bare check rendered success on failure)
- validator page: restore a typed action.error.fieldErrors read example
- polish: error() phrasing + /error/ highlight, Futhermore typo, fieldErrors note
The action store can be captured in $ scopes, so promise must be a QRL
(like submit) rather than a plain function. Runtime already returned a
QRL via $(); this aligns the type.
@maiieul maiieul force-pushed the v2-action-async-signal branch from 453c9f7 to ccb966f Compare June 15, 2026 12:07
valid-lexical-scope rejected class instances captured in $ scopes, but
Qwik serializes any `instanceof Error`. Recognize Error subclasses (e.g.
ServerError from action.error) as serializable, matching the serializer.
@maiieul maiieul force-pushed the v2-action-async-signal branch from ccb966f to c13e4f4 Compare June 15, 2026 12:08
maiieul added 4 commits June 17, 2026 18:46
- AsyncSignal.value no longer leaks the NEEDS_COMPUTATION sentinel in an
  error state — it returns undefined, so {value && ...} is falsy.
- When an errored signal's .error is never read, log a dev-only warning
  (opt into prod with globalThis.qWarnUnhandledErrors = true).
- return fail() and validators now also populate .error (the one failure
  channel); .value.failed stays deprecated.
Covers the action submit flow end-to-end: return fail() populates both
.value.failed and .error, an unread return error() logs the dev-only
unhandled-error warning, and a handled error() stays quiet.
…arning

Adds `unhandledErrorWarning: 'off' | 'dev' | 'all'` (default 'dev') to qwikVite,
injected as a `globalThis.qWarnUnhandledErrors` define. The runtime gate is now
tri-state (`flag ?? qDev`) so 'off' silences dev too and 'all' enables prod.
…rning

Aligns the runtime flag name with the qwikVite `unhandledErrorWarning` option.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Waiting For Review

Development

Successfully merging this pull request may close these issues.

1 participant