cypress-io/cypress · error

Missing event for ${event}

Error message

Missing event for ${event}

What it means

Thrown by EventRegistrar.executeNodeEvent when this._registeredEvents[event] is not a function. The registrar is the bridge that invokes plugin-registered event handlers (e.g. 'before:spec', 'task', 'file:preprocessor') from the plugins child process. Calling executeNodeEvent for an event that no plugin ever registered (or that was reset) hits this guard. It is a contract violation: the caller should have used isRegistered first, or the plugin failed to register the event.

Source

Thrown at packages/data-context/src/data/EventRegistrar.ts:23

export class EventRegistrar {
  private _registeredEvents: Record<string, Function> = {}

  hasNodeEvent (eventName: string) {
    const isRegistered = typeof this._registeredEvents[eventName] === 'function'

    debug('plugin event registered? %o', { eventName, isRegistered })

    return isRegistered
  }

  executeNodeEvent (event: string, args: any[]) {
    debug(`execute plugin event '${event}' Node '${process.version}' with args: %o %o %o`, ...args)

    const evtFn = this._registeredEvents[event]

    if (typeof evtFn !== 'function') {
      throw new Error(`Missing event for ${event}`)
    }

    return evtFn(...args)
  }

  registerEvent (event: string, callback: Function) {
    debug(`register event '${event}'`)

    if (!_.isString(event)) {
      throw new Error(`The plugin register function must be called with an event as its 1st argument. You passed '${event}'.`)
    }

    if (!_.isFunction(callback)) {
      throw new Error(`The plugin register function must be called with a callback function as its 2nd argument. You passed '${callback}'.`)
    }

    this._registeredEvents[event] = callback
  }

View on GitHub (pinned to 0d85fdc912)

Solutions

  1. Check setupNodeEvents in cypress.config.ts: ensure `on('task', ...)` (or whichever event is failing) is reached without throwing.
  2. Wrap early setup in setupNodeEvents in try/catch and log so a registration-time error does not silently abort later registrations.
  3. If you call executeNodeEvent in your own tooling, guard with `if (registrar.isRegistered(event))` first.
  4. Run with DEBUG=cypress:plugins to see the event-registration log.

Example fix

// before
export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      if (config.env.useTasks) on('task', { foo: () => null })
    },
  },
})
// caller invokes cy.task('foo') with useTasks=false -> error 56
// after
setupNodeEvents(on, config) {
  on('task', { foo: () => null }) // always register if you may call it
}
Defensive patterns

Strategy: type-guard

Validate before calling

function callIfRegistered (registrar, event, args) {
  if (registrar.isRegistered(event)) {
    return registrar.executeNodeEvent(event, args)
  }
  // silently skip or log
}

Type guard

function isEventRegistered (registrar: { isRegistered: (e: string) => boolean }, event: string): boolean {
  return registrar.isRegistered(event)
}

Try / catch

try {
  registrar.executeNodeEvent(event, args)
} catch (e) {
  if (/Missing event for/.test(e.message)) {
    // plugin never registered this event; degrade gracefully
    return null
  }
  throw e
}

Prevention

When it happens

Trigger: Cypress server code calls executeNodeEvent('task', args) when no setupNodeEvents handler has called on('task', fn); or a plugin's setupNodeEvents threw before reaching the on('task', ...) registration line, leaving the event unregistered but the server still trying to invoke it.

Common situations: A user's setupNodeEvents threw an error during registration (so partial events were registered), a plugin is gated behind an env flag that was false, or internal server code is invoking an event before plugins finished loading.

Related errors


AI-assisted analysis of cypress-io/cypress@0d85fdc912 (2026-08-12). Data as JSON: /api/errors/924ad68840b9fd9b. Report an issue: GitHub.