[PR #1000] [MERGED] fix(app-router): preserve falsy thrown values in error boundaries #1012

Closed
opened 2026-05-06 13:11:33 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/1000
Author: @NathanDrake2406
Created: 5/1/2026
Status: Merged
Merged: 5/1/2026
Merged by: @james-elicx

Base: mainHead: nathan/fix-falsy-error-boundary


📝 Commits (1)

  • 6a60dcc fix(app-router): preserve falsy thrown values in error boundaries

📊 Changes

6 files changed (+126 additions, -23 deletions)

View changed files

📝 packages/vinext/src/server/app-page-route-wiring.tsx (+2 -2)
📝 packages/vinext/src/shims/error-boundary.tsx (+12 -8)
📝 tests/e2e/app-router/error-handling.spec.ts (+24 -0)
📝 tests/error-boundary.test.ts (+25 -13)
tests/fixtures/app-basic/app/falsy-error-boundary-test/error.tsx (+18 -0)
tests/fixtures/app-basic/app/falsy-error-boundary-test/page.tsx (+45 -0)

📄 Description

What this changes

App Router error boundaries now preserve falsy thrown values such as undefined, null, 0, "", and false instead of treating them as no captured error. Segment error boundary props now accept unknown, matching the fact that JavaScript can throw non-Error values.

Fixes #989.

Why

Next.js fixed the same failure mode in vercel/next.js#93134 via ea541987d1735493c63b52d0b6e673d4435cbb20. The important invariant is that boundary state must distinguish “no error” from “an error was thrown with a falsy value”.

Relevant upstream source:

Approach

  • Changed vinext App Router error boundary state from raw Error | null to null | { thrownValue: unknown }.
  • Kept existing router-control rethrows for not-found, HTTP access fallback, and redirects.
  • Updated App Router route wiring types so error boundary components receive unknown, not an incorrectly narrowed Error.
  • Added unit coverage for the state contract and browser coverage for client components throwing each falsy literal.

Validation

  • vp test run tests/error-boundary.test.ts
  • vp check packages/vinext/src/shims/error-boundary.tsx packages/vinext/src/server/app-page-route-wiring.tsx tests/error-boundary.test.ts tests/e2e/app-router/error-handling.spec.ts tests/fixtures/app-basic/app/falsy-error-boundary-test/error.tsx tests/fixtures/app-basic/app/falsy-error-boundary-test/page.tsx
  • vp run vinext#build
  • PLAYWRIGHT_PROJECT=app-router vp run test:e2e tests/e2e/app-router/error-handling.spec.ts

Risks / follow-ups

This PR intentionally scopes the change to vinext's existing App Router error-boundary shim. The HTTP access fallback boundaries already track explicit boolean/status state, and redirects continue through the existing digest rethrow path.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/1000 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 5/1/2026 **Status:** ✅ Merged **Merged:** 5/1/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `nathan/fix-falsy-error-boundary` --- ### 📝 Commits (1) - [`6a60dcc`](https://github.com/cloudflare/vinext/commit/6a60dcc4467f468969fcbf6efc3a509a6ce07e1c) fix(app-router): preserve falsy thrown values in error boundaries ### 📊 Changes **6 files changed** (+126 additions, -23 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/server/app-page-route-wiring.tsx` (+2 -2) 📝 `packages/vinext/src/shims/error-boundary.tsx` (+12 -8) 📝 `tests/e2e/app-router/error-handling.spec.ts` (+24 -0) 📝 `tests/error-boundary.test.ts` (+25 -13) ➕ `tests/fixtures/app-basic/app/falsy-error-boundary-test/error.tsx` (+18 -0) ➕ `tests/fixtures/app-basic/app/falsy-error-boundary-test/page.tsx` (+45 -0) </details> ### 📄 Description ## What this changes App Router error boundaries now preserve falsy thrown values such as `undefined`, `null`, `0`, `""`, and `false` instead of treating them as no captured error. Segment error boundary props now accept `unknown`, matching the fact that JavaScript can throw non-`Error` values. Fixes #989. ## Why Next.js fixed the same failure mode in [vercel/next.js#93134](https://github.com/vercel/next.js/pull/93134) via [ea541987d1735493c63b52d0b6e673d4435cbb20](https://github.com/vercel/next.js/commit/ea541987d1735493c63b52d0b6e673d4435cbb20). The important invariant is that boundary state must distinguish “no error” from “an error was thrown with a falsy value”. Relevant upstream source: - [Next.js `ErrorBoundaryHandlerState` wraps thrown values](https://github.com/vercel/next.js/blob/ea541987d1735493c63b52d0b6e673d4435cbb20/packages/next/src/client/components/error-boundary.tsx#L36-L64) - [Next.js renders the unwrapped `thrownValue`](https://github.com/vercel/next.js/blob/ea541987d1735493c63b52d0b6e673d4435cbb20/packages/next/src/client/components/error-boundary.tsx#L102-L117) - [Next.js applies the same shape to `unstable_catchError`](https://github.com/vercel/next.js/blob/ea541987d1735493c63b52d0b6e673d4435cbb20/packages/next/src/client/components/catch-error.tsx#L31-L65) - [Next.js falsy throw regression coverage](https://github.com/vercel/next.js/blob/canary/test/e2e/app-dir/errors/index.test.ts) ## Approach - Changed vinext App Router error boundary state from raw `Error | null` to `null | { thrownValue: unknown }`. - Kept existing router-control rethrows for not-found, HTTP access fallback, and redirects. - Updated App Router route wiring types so error boundary components receive `unknown`, not an incorrectly narrowed `Error`. - Added unit coverage for the state contract and browser coverage for client components throwing each falsy literal. ## Validation - `vp test run tests/error-boundary.test.ts` - `vp check packages/vinext/src/shims/error-boundary.tsx packages/vinext/src/server/app-page-route-wiring.tsx tests/error-boundary.test.ts tests/e2e/app-router/error-handling.spec.ts tests/fixtures/app-basic/app/falsy-error-boundary-test/error.tsx tests/fixtures/app-basic/app/falsy-error-boundary-test/page.tsx` - `vp run vinext#build` - `PLAYWRIGHT_PROJECT=app-router vp run test:e2e tests/e2e/app-router/error-handling.spec.ts` ## Risks / follow-ups This PR intentionally scopes the change to vinext's existing App Router error-boundary shim. The HTTP access fallback boundaries already track explicit boolean/status state, and redirects continue through the existing digest rethrow path. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:11:33 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#1012
No description provided.