denoland/deno · error · TypeError

${openContext} could not be iterated because iterator method

Error message

${openContext} could not be iterated because iterator method did not return object, but ${type(iter)}.

What it means

WebIDL async-iterable conversion 'open' step: it calls the stored @@iterator/@@asyncIterator method on the value and requires the returned iterator to be an Object. If a primitive comes back, this TypeError includes the API context (openContext) and the actual type name from webidl's type() ('Undefined', 'String', 'Number', ...).

Source

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

          context,
        );
      }
      sequenceType = "sync";
    }

    return {
      // Fields used by extractBody / callers.
      value: V,
      object: V,
      method,
      type: sequenceType,
      [AsyncSequence]: AsyncSequence,
      // https://webidl.spec.whatwg.org/#async-sequence-open
      open(openContext = context) {
        // 1. Let iterator be ? GetIteratorFromMethod(object, method).
        const iter = FunctionPrototypeCall(method, V);
        if (type(iter) !== "Object") {
          throw new TypeError(
            `${openContext} could not be iterated because iterator method did not return object, but ${
              type(iter)
            }.`,
          );
        }

        // 2. If type is "sync", set iterator to CreateAsyncFromSyncIterator(iterator).
        const asyncIterator = sequenceType === "sync"
          ? createAsyncFromSyncIterator(iter)
          : iter;

        // Capture nextMethod per Iterator Record semantics.
        const nextMethod = asyncIterator.next;

        return {
          // https://webidl.spec.whatwg.org/#async-iterator-get-next-value
          // Exposed as an async iterator protocol shape for callers.
          async next() {

View on GitHub (pinned to f7822238ca)

Solutions

  1. Return an iterator object (usually this) from the @@iterator/@@asyncIterator method
  2. Or delegate: return source[Symbol.asyncIterator]();
  3. Pass a native iterable (Array, Map, Set, ReadableStream) instead of a custom object

Example fix

// before
const body = { [Symbol.asyncIterator]: () => 'not-an-iterator' };
await fetch(url, { body });

// after
const body = { async *[Symbol.asyncIterator]() { yield 'chunk'; } };
await fetch(url, { body });
Defensive patterns

Strategy: validation

Validate before calling

function assertOpenable(v: unknown) {
  const m = (v as any)?.[Symbol.asyncIterator] ?? (v as any)?.[Symbol.iterator];
  if (typeof m !== 'function') return; // absence is a different error
  const iter = m.call(v);
  if (typeof iter !== 'object' || iter === null) {
    throw new TypeError('iterator method must return an iterator object');
  }
}

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: fetch(url, { body: { [Symbol.asyncIterator]: () => 'stream' } }) or any Deno API taking an async sequence where the iterator method returns a primitive instead of an iterator object.

Common situations: Writing [Symbol.asyncIterator]() { return this.items } where items is a string/number; async-iterator methods that return a value instead of this or an iterator; confusing 'the method returns the iterator' with 'the method returns the data'.

Related errors


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