denoland/deno · error · NodeTypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "event" argument must be an instance of Event. Received ${actual}

What it means

dispatchEvent requires its argument to be a real Event: the polyfill checks ObjectPrototypeIsPrototypeOf(globalThis.Event.prototype, event). Plain objects ({ type: 'x' }), strings, or class instances that merely duck-type an Event all throw ERR_INVALID_ARG_TYPE. Subclasses of Event (including CustomEvent) pass the check.

Source

Thrown at ext/node/polyfills/internal/event_target.mjs:704

          MapPrototypeDelete(this[kEvents], type);
        }
        this[kRemoveListener](root.size, type, listener, capture);
        break;
      }
      handler = handler.next;
    }
  }

  /**
   * @param {Event} event
   */
  dispatchEvent(event) {
    if (!isEventTarget(this)) {
      throw new ERR_INVALID_THIS("EventTarget");
    }

    if (!ObjectPrototypeIsPrototypeOf(globalThis.Event.prototype, event)) {
      throw new ERR_INVALID_ARG_TYPE("event", "Event", event);
    }

    if (event[kIsBeingDispatched]) {
      throw new ERR_EVENT_RECURSION(event.type);
    }

    this[kHybridDispatch](event, event.type, event);

    return event.defaultPrevented !== true;
  }

  [kHybridDispatch](nodeValue, type, event) {
    const createEvent = () => {
      if (event === undefined) {
        event = this[kCreateEvent](nodeValue, type);
        event[kTarget] = this;
        event[kIsBeingDispatched] = true;
      }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Wrap the payload: dispatchEvent(new CustomEvent('ping', { detail: data }))
  2. Use new Event(type) when no payload is needed
  3. Make custom event classes extend Event (or CustomEvent) so the prototype check passes
  4. Convert { type, detail } literals at the boundary before dispatching

Example fix

// before
target.dispatchEvent({ type: 'ping', detail: 42 });

// after
target.dispatchEvent(new CustomEvent('ping', { detail: 42 }));
Defensive patterns

Strategy: type-guard

Validate before calling

function dispatch(target, typeOrEvent, detail) {
  const ev = typeOrEvent instanceof Event
    ? typeOrEvent
    : detail === undefined ? new Event(typeOrEvent) : new CustomEvent(typeOrEvent, { detail });
  target.dispatchEvent(ev);
}

Type guard

const isEvent = (v) => v instanceof Event; // matches the polyfill's prototype check

Try / catch

try { target.dispatchEvent(ev); } catch (e) { if (e?.code === 'ERR_INVALID_ARG_TYPE' && /event/.test(e.message)) throw new TypeError('dispatchEvent requires an Event instance'); throw e; }

Prevention

When it happens

Trigger: dispatchEvent({ type: 'ping', detail: 1 }); dispatchEvent('ping'); passing a payload object that was JSON round-tripped; a MockEvent class that implements the shape but does not extend Event; forwarding an EventEmitter-style { type, ... } object into an EventTarget.

Common situations: Porting EventEmitter emit('name', data) calls to EventTarget dispatch; test fixtures that fake events as literals; cross-realm or cross-copy constructs where the object came from a different context and is not a real Event instance.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/32a5d5bea23b5a67. Report an issue: GitHub.