facebook/react · critical · Error

320

320

Error message

Expected ReactFiberErrorDialog.showErrorDialog to be a function.

What it means

react-native-renderer's Fabric entry (ReactFabric.js) validates at module load that react-native's private interface ('react-native/react-private-interface') exports ReactFiberErrorDialog.showErrorDialog, which is how the renderer surfaces uncaught/caught errors to RN's RedBox/LogBox. If the installed react-native version's private interface lacks it, the import itself throws and nothing renders - a build/config problem, not a runtime usage error.

Source

Thrown at packages/react-native-renderer/src/ReactFabric.js:55

  sendAccessibilityEvent,
  getNodeFromInternalInstanceHandle,
  isChildPublicInstance,
} from './ReactNativePublicCompat';
import {getPublicInstanceFromInternalInstanceHandle} from './ReactFiberConfigFabric';

// Module provided by RN:
import {
  ReactFiberErrorDialog,
  createPublicRootInstance,
  type PublicRootInstance,
} from 'react-native/react-private-interface';
import {
  disableLegacyMode,
  enableDefaultTransitionIndicator,
} from 'shared/ReactFeatureFlags';

if (typeof ReactFiberErrorDialog.showErrorDialog !== 'function') {
  throw new Error(
    'Expected ReactFiberErrorDialog.showErrorDialog to be a function.',
  );
}

function nativeOnUncaughtError(
  error: mixed,
  errorInfo: {+componentStack?: ?string},
): void {
  const componentStack =
    errorInfo.componentStack != null ? errorInfo.componentStack : '';
  const logError = ReactFiberErrorDialog.showErrorDialog({
    errorBoundary: null,
    error,
    componentStack,
  });

  // Allow injected showErrorDialog() to prevent default console.error logging.
  // This enables renderers like ReactNative to better manage redbox behavior.

View on GitHub (pinned to eafeac097b)

Solutions

  1. Use the react version pinned by your react-native release (check the RN changelog/peerDependencies) and reinstall so exactly one pair exists.
  2. Inspect Metro resolver.extraNodeModules / babel-module-resolver aliases and jest moduleNameMapper for stale react-native mocks that hide react-private-interface.
  3. Run 'npm ls react react-native' (or yarn equivalent) to confirm no duplicate or skewed copies, then reset Metro/watchman caches and rebuild.

Example fix

// jest.config.js - before
moduleNameMapper: {'^react-native$': '<rootDir>/__mocks__/react-native.js'}

// after - mock only the private interface, keeping its real shape
moduleNameMapper: {
  '^react-native/react-private-interface$':
    '<rootDir>/__mocks__/react-private-interface.js',
}
// __mocks__/react-private-interface.js must export ReactFiberErrorDialog with a showErrorDialog function
Defensive patterns

Strategy: validation

Validate before calling

import {ReactFiberErrorDialog} from 'react-native/react-private-interface';
if (
  ReactFiberErrorDialog == null ||
  typeof ReactFiberErrorDialog.showErrorDialog !== 'function'
) {
  throw new Error(
    'react/react-native mismatch: use the react release pinned by your react-native version',
  );
}

Prevention

When it happens

Trigger: Loading ReactFabric against a react-native whose react-private-interface does not export ReactFiberErrorDialog.showErrorDialog - a react vs react-native version skew, a Metro resolver alias, or a Jest moduleNameMapper mock of react-native that omits the private interface.

Common situations: Upgrading react independently of react-native (RN pins an exact react release); duplicate hoisted copies in node_modules; coarse jest mocks of 'react-native'; community RN forks with divergent internals.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/28f2b63ec5317f37. Report an issue: GitHub.