You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Review fixes from the Claude Code review pass and Cursor Bugbot on PR #3933:
1. Dev-mode hydration logger no longer swallows React's default
reporting or the component stack. The error is default-reported
exactly once (reportError, falling back to console.error — mirroring
React's own default) so window-'error' tooling keeps working, and the
branded line now includes errorInfo.componentStack.
2. New buildRootErrorCallbackOptions option
defaultReportingHandledInternally: Pro's RSC-wrapped hydrate paths
pass it so the chained internal handler remains the single default
reporter and the dev logger emits only its supplemental branded line
(no second full error dump in development). Added a Pro test covering
the chained dev path with railsEnv development.
3. getRootErrorHandlers now returns a snapshot copy so callers cannot
mutate the internal registration and bypass validation.
4. Extracted the three byte-identical isThenable copies into
packages/react-on-rails/src/isThenable.ts (exported as
react-on-rails/@internal/isThenable) and removed the MUST-SYNC
thenable-guard duplication note from the Pro renderer.
5. Partial rootErrorHandlers updates now merge per key (consistent with
the other setOptions keys): setting only one callback keeps the
others; an explicit undefined clears just that key; resetOptions
still clears all. setOptions stores the merged result so
option('rootErrorHandlers') reflects the effective registration.
Docs (guide, JS API reference, type JSDoc) and the changelog entry
updated to describe the preserved default reporting, component stack,
and merge semantics.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,7 +26,7 @@ After a release, run `/update-changelog` in Claude Code to analyze commits, writ
26
26
27
27
#### Added
28
28
29
-
- **React 19 root error callbacks**: `ReactOnRails.setOptions({ rootErrorHandlers: { onRecoverableError, onCaughtError, onUncaughtError } })` registers React's root error callbacks globally; React on Rails applies them to every `hydrateRoot`/`createRoot` call it makes and invokes them with an extra context argument containing the component name and DOM id. In development, recoverable hydration errors now log an actionable React on Rails message (component name, dom id, and a link to the new [Debugging Hydration Mismatches guide](https://reactonrails.com/docs/building-features/debugging-hydration-mismatches)) instead of React's bare console line. On React <19 (and <18 for `onRecoverableError`), registration is a graceful no-op with a console warning. On React on Rails Pro RSC/streaming hydration paths, user callbacks chain with (never replace) Pro's internal recoverable-error handler. Addresses [Issue 3892](https://github.com/shakacode/react_on_rails/issues/3892). [PR 3933](https://github.com/shakacode/react_on_rails/pull/3933) by [justin808](https://github.com/justin808).
29
+
- **React 19 root error callbacks**: `ReactOnRails.setOptions({ rootErrorHandlers: { onRecoverableError, onCaughtError, onUncaughtError } })` registers React's root error callbacks globally; React on Rails applies them to every `hydrateRoot`/`createRoot` call it makes and invokes them with an extra context argument containing the component name and DOM id. In development, recoverable hydration errors now log an actionable React on Rails message (component name, dom id, component stack, and a link to the new [Debugging Hydration Mismatches guide](https://reactonrails.com/docs/building-features/debugging-hydration-mismatches)) alongside React's default error reporting, which stays intact so window-'error'-based tooling keeps working. Partial `rootErrorHandlers` updates merge per key, so registering one callback later does not drop the others. On React <19 (and <18 for `onRecoverableError`), registration is a graceful no-op with a console warning. On React on Rails Pro RSC/streaming hydration paths, user callbacks chain with (never replace) Pro's internal recoverable-error handler. Addresses [Issue 3892](https://github.com/shakacode/react_on_rails/issues/3892). [PR 3933](https://github.com/shakacode/react_on_rails/pull/3933) by [justin808](https://github.com/justin808).
Copy file name to clipboardExpand all lines: docs/oss/building-features/debugging-hydration-mismatches.md
+7-2Lines changed: 7 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,12 +8,16 @@ Rails apps hit a set of systematic causes that JavaScript-only frameworks rarely
8
8
9
9
### Development default
10
10
11
-
When `Rails.env.development?`, React on Rails automatically logs every recoverable hydration error with the component name, the DOM id, and a link to this guide — replacing React's bare console line:
11
+
When `Rails.env.development?`, React on Rails automatically logs every recoverable hydration error with the component name, the DOM id, the component stack (when React provides one), and a link to this guide:
React's default error reporting is preserved: the error itself is still reported once via `reportError` (falling back to `console.error`), so dev overlays and other window-`'error'`-based tooling keep working. The branded line is supplemental context. On React on Rails Pro RSC hydration paths, Pro's internal handler already reports the error, so only the supplemental line is added — each error is reported exactly once either way.
20
+
17
21
No setup is required. The default logger runs in addition to any callback you register.
18
22
19
23
### Registering root error callbacks (React 19)
@@ -51,7 +55,8 @@ Each callback receives React's original `(error, errorInfo)` arguments plus a `c
51
55
52
56
Notes:
53
57
54
-
-**Register before rendering.** Callbacks apply to roots created after registration; register them in the same pack file where you call `ReactOnRails.register`.
58
+
-**Register before rendering.** Each root captures the callbacks registered at the moment it is created; register them in the same pack file where you call `ReactOnRails.register`.
59
+
-**Partial updates merge per key.** A later `setOptions({ rootErrorHandlers: { onCaughtError } })` keeps a previously registered `onRecoverableError`/`onUncaughtError`. Pass an explicit `undefined` for a key to clear just that callback; `ReactOnRails.resetOptions()` clears all of them.
55
60
-**React version support:**`onRecoverableError` requires React 18+; `onCaughtError`/`onUncaughtError` require React 19. On older React versions, registration is a graceful no-op and React on Rails logs a one-time `console.warn`.
56
61
-**React on Rails Pro:** on RSC/streaming hydration paths, Pro installs an internal `onRecoverableError` for its own bookkeeping. Your callback is chained after it — both always run, and Pro's internal control-flow signals (such as the `RSCRoute``ssr: false` bailout) are filtered out of both so they never reach your error reporter.
57
62
-**Per-component overrides** are not currently supported; the global registration above is the blessed route.
0 commit comments