Skip to content

Bug: Browser-based handling of recoverable errors is to strict - use console instead of the reportError API #24563

@gurkerl83

Description

@gurkerl83

React handles recoverable errors in onRecoverableError. Either a custom function is passed to hydrateRoot; otherwise React's default implementation is used, which uses the browser's reportError function. Errors that are recoverable in isolation are always reported to the user in a modal-style error dialogue, and are not handled quietly.

NextJs uses only two arguments (Dom element, React element) when calling hydrateRoot. The third possible argument to specify hydrate options along with the onRecoverableError field, in which the error response of recoverable errors can be adjusted, is not used at all.

In principle, the problem can be addressed on the NextJs or React side, but an adjustment is necessary on the respective side.

Option 1: NextJs - Extension of the NextJs configuration
NextJs does not allow an option in its configuration to specify hydrate options (specifically onRecoverableError) that are passed from NextJs to hydrateRoot.

Con: Valid only for NextJs, other libraries that hide the call to hydrateRoot from the user and do not allow hydrate options are still affected by the issue.

Option 2: Adaptation of React's default implementation to onRecoverableError

Errors related to suspense are called recoverable. These are resolved through React internal workflows by reverting to a client-based rendering within a Suspense Boundary. As these errors are handled, jumping back to a client-based rendering does not constitute a critical error. A hint in the console about the cause that led to the switch to a client-based rendering should be sufficient.

Extract from ReactDOMRoot

const defaultOnRecoverableError =
   typeof reportError === 'function'
      ?  // In modern browsers, reportError will dispatch an error event, emulating an uncaught JavaScript error.
      reportError
      : (error: mixed) => {
         // In older browsers and test environments, fallback to console.error.
         // eslint-disable-next-line react-internal/no-production-logging, react-internal/warning-args.
      console.error(error);
      };
  • Removal of browser-based API reportError to handle recoverable errors.

https://developer.mozilla.org/en-US/docs/Web/API/reportError

As pointed out in the comment, an uncaught error is thrown even if it was classified as recoverable within React. React internal processes have responded to such errors, for example by server-side and client-side content not matching.

The error caused by reportError must in turn be caught by a global error handler. This seems to be a bit excessive.

window.onerror = function(message, source, lineno, colno, error) {
  console.log('message:' + error.message + ', lineno: ' + lineno );
  return true;
};
  • Output the error only in the console, as is the case in older browsers and test environments.

In React based libraries that do not allow or support configuration of hydrate options, the problem must be described as recurring. Especially in background that React notices recoverable errors and actively counteracts them, conversely should resort to a less aggressive behaviour to bring this to the developer's attention.

ReportError is a very young API - Supported from October 2021 in Edge, Firefox and Chrome, not before.

https://caniuse.com/?search=reportError

LogRecoverableError was originally introduced in ReactDOMHostConfig.
848e802

The following refactoring has changed the name and position.
efd8f64

logRecoverableError => defaultOnRecoverableError
ReactDOMHostConfig => ReactDomRoot

I will open an issue in NextJs and React respectively.

Thx!

React version: 18.1.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    Resolution: StaleAutomatically closed due to inactivityStatus: UnconfirmedA potential issue that we haven't yet confirmed as a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions