denoland/deno · error · TypeError

MessageEvent constructor: eventInitDict.ports (${formatForRa

Error message

MessageEvent constructor: eventInitDict.ports (${formatForRaw(ports)}) is not iterable.

What it means

The MessageEvent constructor validates eventInitDict.ports, typed in the HTML spec as FrozenArray<MessagePort>. Any non-null value must be an object exposing Symbol.iterator (ext/web/02_event.js:1348-1357); anything else throws TypeError '... is not iterable'. The wording deliberately matches Node's assertion messages so node_compat tests pass while the shape stays WHATWG. The classic trigger is passing a single MessagePort instead of an array containing it.

Source

Thrown at ext/web/02_event.js:1354

      cancelable: eventInitDict?.cancelable ?? false,
      composed: eventInitDict?.composed ?? false,
    });

    this.data = eventInitDict?.data ?? null;
    const ports = eventInitDict?.ports;
    if (ports == null) {
      // `ports` is a FrozenArray<MessagePort> per the HTML spec, so the
      // exposed array must be read-only.
      this.ports = ObjectFreeze([]);
    } else {
      // MessageEvent ports: iterable validation + per-element MessagePort
      // type check. Matches the messages Node asserts on so the
      // node_compat tests pass while still being WHATWG-shaped.
      if (
        ports === null || typeof ports !== "object" ||
        ports[SymbolIterator] === undefined
      ) {
        throw new TypeError(
          `MessageEvent constructor: eventInitDict.ports (${
            formatForRaw(ports)
          }) is not iterable.`,
        );
      }
      const MessagePortProto = getMessagePortPrototype();
      const arr = [];
      let i = 0;
      // Iterate using the user's own iterator so values that aren't real
      // arrays (e.g. a `RegExp` with a custom `Symbol.iterator` -- covered
      // by WPT's no-regexp-special-casing test) still produce the
      // expected `ports` array. SafeArrayIterator can't be used here
      // because it walks the value as if it were an Array.
      // deno-lint-ignore deno-internal/prefer-primordials
      for (const p of ports) {
        if (
          p === null || typeof p !== "object" ||
          !ObjectPrototypeIsPrototypeOf(MessagePortProto, p)

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Wrap ports in an array: new MessageEvent('message', { data, ports: [channel.port1] }).
  2. Omit ports (or pass null/undefined) when no ports were transferred — the constructor freezes an empty array.
  3. Validate third-party payloads before constructing: check ports == null || (typeof ports === 'object' && typeof ports[Symbol.iterator] === 'function').

Example fix

// before
new MessageEvent('message', { data, ports: channel.port1 });
// TypeError: MessageEvent constructor: eventInitDict.ports ([object MessagePort]) is not iterable.

// after
new MessageEvent('message', { data, ports: [channel.port1] });
Defensive patterns

Strategy: type-guard

Validate before calling

const raw = eventInit.ports;
if (raw != null && (typeof raw !== 'object' || typeof raw[Symbol.iterator] !== 'function')) {
  throw new TypeError('eventInitDict.ports must be an array of MessagePort');
}
new MessageEvent('message', { ...eventInit, ports: raw == null ? [] : [...raw] });

Type guard

function isPortList(v) {
  return v == null ||
    (typeof v === 'object' && typeof v[Symbol.iterator] === 'function');
}

Prevention

When it happens

Trigger: new MessageEvent('message', { data, ports: channel.port1 }) — a single MessagePort is an object but has no Symbol.iterator; also ports: 'abc', ports: 123, or ports: {} (no iterator). ports omitted, null, or an iterable array are accepted.

Common situations: Transferring exactly one port and passing it unwrapped; test fixtures for postMessage/messagepassing written by Node developers (Node tolerates different shapes); polyfills that accept either a port or an array and forward verbatim.

Related errors


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