denoland/deno · error · TypeError

${name} is not a function

Error message

${name} is not a function

What it means

Implements ECMA-262 GetMethod for WebIDL: reads property P on V; null/undefined means 'absent', but any other non-callable value throws TypeError. Symbol keys are formatted with Symbol.prototype.toString so the message reads engine-style, e.g. 'Symbol(aaa) is not a function'. Used by iterator/async-iterator protocol lookups (isAsyncSequence) and converters.

Source

Thrown at ext/webidl/00_webidl.js:1010

        `${context}, index ${array.length}`,
        opts,
      );
      ArrayPrototypePush(array, val);
    }
    return array;
  };
}

// https://tc39.es/ecma262/#sec-getmethod
function getMethod(V, P) {
  const func = V[P];
  if (func === undefined || func === null) {
    return undefined;
  }
  if (typeof func !== "function") {
    // Match engine-style key formatting: Symbol(aaa), not the bare description.
    const name = typeof P === "symbol" ? SymbolPrototypeToString(P) : P;
    throw new TypeError(`${name} is not a function`);
  }
  return func;
}

// Whether V is convertible to an IDL async_sequence (has a usable
// @@asyncIterator or @@iterator method). Uses GetMethod, so non-callable
// methods throw TypeError (same as conversion / union matching).
function isAsyncSequence(obj) {
  if (type(obj) !== "Object") {
    return false;
  }
  if (getMethod(obj, SymbolAsyncIterator) !== undefined) {
    return true;
  }
  return getMethod(obj, SymbolIterator) !== undefined;
}

// https://tc39.es/ecma262/#sec-createasyncfromsynciterator

View on GitHub (pinned to f7822238ca)

Solutions

  1. Make the property a real method: [Symbol.asyncIterator]() { return this; }
  2. Or set the property to null/undefined (or delete it) so it counts as absent instead of invalid
  3. Never store iterator objects under @@iterator/@@asyncIterator keys - store the iterable and let the method be invoked

Example fix

// before
const body = { [Symbol.asyncIterator]: source[Symbol.asyncIterator]() }; // object, not a function

// after
const body = { [Symbol.asyncIterator]() { return source[Symbol.asyncIterator](); } };
Defensive patterns

Strategy: type-guard

Validate before calling

function checkProtocolMethods(v: object, key: symbol | string) {
  const m = (v as any)[key];
  if (m != null && typeof m !== 'function') {
    throw new TypeError(`${String(key)} must be a function or null`);
  }
}
checkProtocolMethods(body, Symbol.asyncIterator);

Type guard

const isAsyncIterable = (v: unknown): v is AsyncIterable<unknown> =>
  v != null && typeof (v as Record<PropertyKey, unknown>)[Symbol.asyncIterator] === 'function';

Prevention

When it happens

Trigger: Passing an object used as an iterable/async-iterable (e.g. a fetch body) where @@asyncIterator or @@iterator exists but is not callable, e.g. { [Symbol.asyncIterator]: 42 } or { [Symbol.iterator]: someArray }.

Common situations: Storing an already-called iterator under the symbol key instead of a method ({ [Symbol.asyncIterator]: stream[Symbol.asyncIterator]() }), spreading config objects that overwrite protocol methods with data values, polyfills assigning non-callable symbol properties.

Related errors


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