cypress-io/cypress · error

The plugin register function must be called with a callback

Error message

The plugin register function must be called with a callback function as its 2nd argument. You passed '${callback}'.

What it means

Thrown by EventRegistrar.registerEvent when its second argument fails _.isFunction. After the string guard on event, the registrar verifies the callback is actually callable; passing a plain object, undefined, or a non-function value (e.g. forgetting to wrap a handler in an object for the 'task' event) triggers this guard.

Source

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

    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
  }

  reset () {
    this._registeredEvents = {}
  }
}

View on GitHub (pinned to 0d85fdc912)

Solutions

  1. Ensure the second argument to on() is a function (or for 'task' an object whose values are all functions).
  2. If importing a handler, verify the import is defined and is a function.
  3. Add a `typeof callback === 'function'` check in your plugin before on() if the handler is dynamically resolved.
  4. Inspect the echoed value in the error message — it shows exactly what was passed.

Example fix

// before
setupNodeEvents(on) { on('before:spec', { run: () => null }) } // object, not fn
// after
setupNodeEvents(on) { on('before:spec', () => null) }
Defensive patterns

Strategy: type-guard

Validate before calling

function safeRegister (registrar, event, cb) {
  if (typeof event !== 'string') throw new TypeError('event must be a string')
  if (typeof cb !== 'function') throw new TypeError('callback must be a function')
  registrar.registerEvent(event, cb)
}

Type guard

function isHandler (v: unknown): v is Function {
  return typeof v === 'function'
}

Prevention

When it happens

Trigger: A plugin calls on('task', { foo: null }) (task handlers must be a map of functions but the registrar wraps it; passing a non-function at the top level fails), or on('before:spec', someObject) where someObject is not a function. Also when destructuring a handler from a module that does not export it.

Common situations: Forgetting the function wrapper around an event handler, passing a config object instead of a callback, or importing a handler that does not exist (undefined).

Related errors


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