facebook/react · error · Error

97

97

Error message

EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `${pluginName}` does not.

What it means

Every legacy event plugin must implement extractEvents, the hook the dispatch loop calls to build synthetic events for a top-level event; the registry throws at injection time when a module lacks it. The message names the offending plugin so the bad module is easy to spot.

Source

Thrown at packages/react-native-renderer/src/legacy-events/EventPluginRegistry.js:60

  }
  for (const pluginName in namesToPlugins) {
    const pluginModule = namesToPlugins[pluginName];
    // $FlowFixMe[incompatible-use] found when upgrading Flow
    const pluginIndex = eventPluginOrder.indexOf(pluginName);

    if (pluginIndex <= -1) {
      throw new Error(
        'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
          `the plugin ordering, \`${pluginName}\`.`,
      );
    }

    if (plugins[pluginIndex]) {
      continue;
    }

    if (!pluginModule.extractEvents) {
      throw new Error(
        'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
          `method, but \`${pluginName}\` does not.`,
      );
    }

    plugins[pluginIndex] = pluginModule;
    const publishedEvents = pluginModule.eventTypes;
    for (const eventName in publishedEvents) {
      if (
        !publishEventForPlugin(
          publishedEvents[eventName],
          pluginModule,
          eventName,
        )
      ) {
        throw new Error(
          `EventPluginRegistry: Failed to publish event \`${eventName}\` for plugin \`${pluginName}\`.`,
        );

View on GitHub (pinned to eafeac097b)

Solutions

  1. Implement extractEvents on the plugin module (returning null for events it wants to ignore).
  2. Remove the module from injection if it is not meant to be a dispatch plugin.
  3. Verify the object actually reaching the registry has the right shape (not a module namespace or the module's default).

Example fix

// before
const MyPlugin = {eventTypes: {/* ... */}};

// after
const MyPlugin = {
  eventTypes: {/* ... */},
  extractEvents(topLevelType, targetInst, nativeEvent, eventTarget) {
    return null;
  },
};
Defensive patterns

Strategy: type-guard

Type guard

const isLegacyPluginModule = module =>
  module != null && typeof module.extractEvents === 'function';
const pluginsToInject = {MyPlugin};
for (const [name, module] of Object.entries(pluginsToInject)) {
  if (!isLegacyPluginModule(module)) {
    throw new Error(`Plugin '${name}' must implement extractEvents`);
  }
}
injectEventPluginsByName(pluginsToInject);

Prevention

When it happens

Trigger: Injecting a plugin module without an extractEvents method (or with it renamed/mistyped) via injectEventPluginsByName - for example a partial port or a module namespace/default-export mixup that yields the wrong object shape.

Common situations: Porting plugins from newer event systems that don't use extractEvents; incomplete plugin implementations; broken transpilation or module resolution of plugin files.

Related errors


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