Skip to content

fix(dev-overlay): surface attribute-only hydration mismatches as Cons…#2706

Draft
MaxtuneLee wants to merge 3 commits into
cloudflare:mainfrom
MaxtuneLee:feat/dev-overlay-console-error
Draft

fix(dev-overlay): surface attribute-only hydration mismatches as Cons…#2706
MaxtuneLee wants to merge 3 commits into
cloudflare:mainfrom
MaxtuneLee:feat/dev-overlay-console-error

Conversation

@MaxtuneLee

Copy link
Copy Markdown
Contributor

Problem

Fixes #2705

React 19 reports an attribute-only hydration mismatch through console.error only. vinext's dev overlay listened to onCaughtError/onUncaughtError, window error/unhandledrejection events, and Vite HMR errors, but not console.error, so this case surfaced nothing in the overlay.

What changed

  • Wired onRecoverableError (devOnRecoverableError) for the first time, so recoverable hydration mismatches (text/element-tree) surface as Recoverable Error instead of falling through to the window error listener and getting mislabeled as Unhandled Script Error.
  • Patched console.error, only messages matching React's attribute-only hydration regex (isAttributeOnlyHydrationWarningMessage in dev-console-error.ts) open the overlay, as a new console-error source labeled Console Error. Every other console.error call is left exactly as before.
  • Added structural duplicate detection to the overlay store (dev-error-overlay-store.ts's reportToOverlay / isSameReportedError): two reports only count as the same failure when message, stack, and React's owner stack (captureOwnerStack(), captured synchronously at report time) all match. This replaces an earlier text-plus-1s-window dedup approach, and this will still keep the same attribute warning from two different components (identical message text) from collapsing into one entry.
  • Wired the console.error patch into both routers through the shared installDevErrorOverlay() installer: App Router via app-browser-entry.ts, Pages Router via pages-dev-hydration.ts / pages-client-entry.ts.

Correspondence with Next.js

  • devOnRecoverableError mirrors client/react-client-callbacks/on-recoverable-error.ts's onRecoverableError.
  • The dedup is ported directly from next-devtools/dev-overlay/shared.ts and stitched-error.ts; vinext stores the owner stack as a plain string field instead of a WeakMap<Error, string> since the overlay store never retains the raw Error object.

Testing

  • Unit: tests/dev-console-error.test.ts, tests/app-browser-entry.test.ts, all green.
  • E2E: tests/e2e/app-router/dev-error-overlay.spec.ts and new tests/e2e/pages-router/dev-overlay-hydration.spec.ts, against new fixtures (tests/fixtures/app-basic/app/dev-overlay-hydration/*, tests/fixtures/pages-basic/pages/dev-overlay-hydration.tsx) reproducing the attribute-only mismatch. All green.

MaxtuneLee and others added 2 commits July 25, 2026 17:48
…ole Error

React 19 reports an attribute-only hydration mismatch through console.error
only -- it never calls onRecoverableError and never patches the mismatched
attribute. vinext's dev overlay listened to onCaughtError/onUncaughtError,
window error/unhandledrejection events, and Vite HMR errors, but not
console.error, so this case surfaced nothing in the overlay.

- Wire onRecoverableError (devOnRecoverableError) for the first time, so
  recoverable hydration mismatches (text/element-tree) surface as
  "Recoverable Error" instead of falling through to the window error
  listener mislabeled as "Unhandled Script Error".
- Patch console.error, narrowly gated: only messages matching React's
  attribute-only hydration regex open the overlay (as "Console Error");
  every other console.error call is left exactly as before. General
  console.error interception (matching Next.js's broader Console Error
  behavior for any console.error call) is intentionally out of scope here
  and continues on a follow-up branch.
@pkg-pr-new

pkg-pr-new Bot commented Jul 25, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2706
npm i https://pkg.pr.new/create-vinext-app@2706
npm i https://pkg.pr.new/@vinext/types@2706
npm i https://pkg.pr.new/vinext@2706

commit: 434d4e5

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared 434d4e5 against base 05eee9f using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 132.4 KB 132.4 KB ⚫ -0.0%
Client entry size (gzip) vinext 119.7 KB 119.7 KB ⚫ -0.0%
Dev server cold start vinext 2.78 s 2.77 s ⚫ -0.4%
Production build time vinext 3.08 s 3.05 s ⚫ -1.0%
RSC entry closure size (gzip) vinext 103.3 KB 103.3 KB ⚫ -0.0%
Server bundle size (gzip) vinext 177.8 KB 177.8 KB ⚫ -0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

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.

Attribute hydration mismatches are missing from the dev overlay

1 participant