denoland/deno · error · TypeError

The iterator.return() method must return an object

Error message

The iterator.return() method must return an object

What it means

The manual async-from-sync wrapper's return() runs when the consumer closes the iterator early (break, throw, cancellation). It looks up the sync iterator's optional return() via getMethod; if the method exists, its (awaited) result must be an Object or this TypeError is thrown.

Source

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

      // AsyncFromSyncIteratorContinuation awaits the yielded value so that
      // sync sources of promises (e.g. arrays of Promises) unwrap.
      return {
        done: false,
        value: await iterResult.value,
      };
    },
    async return(reason) {
      const returnMethod = getMethod(syncIterator, "return");
      if (returnMethod === undefined) {
        return { done: true, value: undefined };
      }
      const returnResult = await FunctionPrototypeCall(
        returnMethod,
        syncIterator,
        reason,
      );
      if (type(returnResult) !== "Object") {
        throw new TypeError(
          "The iterator.return() method must return an object",
        );
      }
      return { done: true, value: undefined };
    },
    [SymbolAsyncIterator]() {
      return this;
    },
  };
}

const AsyncSequence = Symbol("[[asyncSequence]]");

// https://webidl.spec.whatwg.org/#js-async-iterable
// https://webidl.spec.whatwg.org/#async-sequence-open
function createAsyncSequenceConverter(converter) {
  return function (
    V,

View on GitHub (pinned to f7822238ca)

Solutions

  1. Return an object from return(): return { done: true };
  2. Or omit return() entirely - an absent return method is skipped, not an error
  3. When delegating to an inner iterator, return its result object: return inner.return?.() ?? { done: true }

Example fix

// before
[Symbol.iterator]() {
  return { next: () => ({ done: false, value: 1 }), return() { cleanup(); } };
}

// after
[Symbol.iterator]() {
  return { next: () => ({ done: false, value: 1 }), return() { cleanup(); return { done: true }; } };
}
Defensive patterns

Strategy: validation

Type guard

interface CloseableIterator<T> extends Iterator<T> {
  return?(value?: unknown): IteratorResult<T>;
}
// Custom iterators typed as CloseableIterator<T> force return() to yield an object.

Prevention

When it happens

Trigger: A custom sync iterator used as async-iterable input with a cleanup return() that returns a primitive or nothing: return() { cleanup(); } (implicit undefined), return: () => null, or return: () => true - and the consumer then terminates iteration early.

Common situations: Adding cleanup hooks that forget to return a value; porting iterator code where return() was void; returning a boolean status or a resource id (number) from return().

Related errors


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