facebook/react · error · Error

233

233

Error message

Unsupported top level event type "${topLevelType}" dispatched

What it means

React Native's legacy event bridge resolves each incoming native top-level event name against the view-config-derived customBubblingEventTypes / customDirectEventTypes registries; a name present in neither throws at extractEvents time. Concretely, the native side dispatched an event that JS never registered because its ViewManager does not declare it.

Source

Thrown at packages/react-native-renderer/src/ReactNativeBridgeEventPlugin.js:186

const ReactNativeBridgeEventPlugin: LegacyPluginModule<AnyNativeEvent> = {
  eventTypes: {} as EventTypes,

  extractEvents: function (
    topLevelType: TopLevelType,
    targetInst: null | Object,
    nativeEvent: AnyNativeEvent,
    nativeEventTarget: null | Object,
  ): ?Object {
    if (targetInst == null) {
      // Probably a node belonging to another renderer's tree.
      return null;
    }
    const bubbleDispatchConfig = customBubblingEventTypes[topLevelType];
    const directDispatchConfig = customDirectEventTypes[topLevelType];

    if (!bubbleDispatchConfig && !directDispatchConfig) {
      throw new Error(
        // $FlowFixMe[incompatible-type] - Flow doesn't like this string coercion because DOMTopLevelEventType is opaque
        `Unsupported top level event type "${topLevelType}" dispatched`,
      );
    }

    const event = SyntheticEvent.getPooled(
      bubbleDispatchConfig || directDispatchConfig,
      targetInst,
      nativeEvent,
      nativeEventTarget,
    );
    if (bubbleDispatchConfig) {
      const skipBubbling =
        event != null &&
        event.dispatchConfig.phasedRegistrationNames != null &&
        event.dispatchConfig.phasedRegistrationNames.skipBubbling;
      if (skipBubbling) {
        accumulateCapturePhaseDispatches(event);

View on GitHub (pinned to eafeac097b)

Solutions

  1. Declare the event in the native ViewManager (e.g. the codegen events array with the exact top-prefixed name being dispatched) and rebuild the app.
  2. Verify the event name matches on both sides, case-sensitive, including the top prefix used for registration.
  3. If the target node may belong to another renderer, guard the dispatch on the native side - targetInst == null is ignored, but unregistered event names are not.

Example fix

// before - native view emits 'quantityChanged' but never declares it
// (RCTEventEmitter receiveEvent(..., 'quantityChanged', ...))

// after - declare it in the codegen spec so JS registers it
// NativeCounter.js
export default codegenNativeComponent('Counter', {
  interfaceName: 'RCTCounter',
  events: [{name: 'topQuantityChanged', bubbling: false}],
});
Defensive patterns

Strategy: validation

Validate before calling

import {UIManager} from 'react-native';
function isEventRegistered(viewName, eventName) {
  const viewConfig = UIManager.getViewManagerConfig(viewName);
  return Boolean(
    viewConfig?.Manager?.directEventTypes?.[eventName] ||
      viewConfig?.Manager?.bubblingEventTypes?.[eventName],
  );
}
if (!isEventRegistered('Counter', 'topQuantityChanged')) {
  throw new Error(
    'Declare topQuantityChanged on the native ViewManager before dispatching it',
  );
}

Prevention

When it happens

Trigger: A native view dispatches an event whose name is not declared in its ViewManager's event tables: a custom native component emitting an event without registering it (codegen directEvents/bubblingEvents), a casing or spelling mismatch between the native constant and the dispatched name, or an event sent for a node owned by another renderer.

Common situations: Custom native modules; adding a native event but not rebuilding/regenerating native code; Fabric codegen event-name differences between iOS and Android; typos in the 'top'-prefixed event constant.

Related errors


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