denoland/deno · error · TypeError

Failed to execute 'observe' on 'PerformanceObserver': 'entry

Error message

Failed to execute 'observe' on 'PerformanceObserver': 'entryTypes' must be an array.

What it means

When observe() is called with `entryTypes`, the Web Performance API requires it to be an array of strings. Deno checks Array.isArray immediately in ext/web/15_performance.js and throws a TypeError for anything else. After the check, unsupported type names are silently filtered against PerformanceObserver.supportedEntryTypes, which in Deno is ["mark", "measure"] — filtering all entries out just makes observe() a no-op (returns without observing).

Source

Thrown at ext/web/15_performance.js:526

    const { entryTypes, type } = options;

    if (entryTypes !== undefined && type !== undefined) {
      throw new TypeError(
        `${prefix}: Cannot specify both 'entryTypes' and 'type'.`,
      );
    }

    if (entryTypes === undefined && type === undefined) {
      throw new TypeError(
        `${prefix}: Either 'entryTypes' or 'type' must be specified.`,
      );
    }

    let types;
    if (entryTypes !== undefined) {
      if (!ArrayIsArray(entryTypes)) {
        throw new TypeError(`${prefix}: 'entryTypes' must be an array.`);
      }
      types = ArrayPrototypeFilter(
        entryTypes,
        (t) =>
          ArrayPrototypeIncludes(PerformanceObserver.supportedEntryTypes, t),
      );
      if (types.length === 0) {
        return;
      }
    } else {
      if (
        !ArrayPrototypeIncludes(PerformanceObserver.supportedEntryTypes, type)
      ) {
        return;
      }
      types = [type];
    }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Wrap the value in an array: observe({ entryTypes: ["mark"] }).
  2. If the value arrives as a string list, split it first: options.entryTypes.split(",").map((s) => s.trim()).
  3. Use the singular `type` option instead when observing exactly one entry type.
  4. Stick to "mark" and "measure" — other names are silently dropped in Deno.

Example fix

// before
observer.observe({ entryTypes: "mark" });

// after
observer.observe({ entryTypes: ["mark"] });
Defensive patterns

Strategy: type-guard

Validate before calling

if (!Array.isArray(opts.entryTypes)) {
  opts.entryTypes = [String(opts.entryTypes)];
}
observer.observe(opts);

Type guard

function isEntryTypesArray(v) {
  return Array.isArray(v) && v.every((t) => typeof t === "string");
}

Try / catch

try { observer.observe(opts); } catch (e) { if (e instanceof TypeError && e.message.includes("must be an array")) { opts.entryTypes = [opts.entryTypes]; observer.observe(opts); } else throw e; }

Prevention

When it happens

Trigger: observe({ entryTypes: "mark" }) — a bare string instead of a one-element array; passing a Set, comma-separated list, or iterable; passing an object like { 0: "mark" } that is not a real Array.

Common situations: Single-type observation where the author forgot the brackets; receiving the list as a delimited string from config and forgetting to split it; mixing up the entryTypes form with the type form (type takes a string, entryTypes takes an array).

Understand the failure class

Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.

Related errors


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