denoland/deno · error · TypeError

The iterator.next() method must return an object

Error message

The iterator.next() method must return an object

What it means

When a sync iterable is supplied where an async sequence is required, Deno wraps it in a manual %AsyncFromSyncIteratorPrototype%. Each call to the sync iterator's next() must return an Object (an IteratorResult); primitives throw this TypeError before the value is awaited.

Source

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

  }
  if (getMethod(obj, SymbolAsyncIterator) !== undefined) {
    return true;
  }
  return getMethod(obj, SymbolIterator) !== undefined;
}

// https://tc39.es/ecma262/#sec-createasyncfromsynciterator
// Manual %AsyncFromSyncIteratorPrototype% so we never go through yield* /
// user-visible @@iterator lookup (primordials-safe).
function createAsyncFromSyncIterator(syncIterator) {
  // Capture [[NextMethod]] as in GetIteratorDirect / Iterator Record.
  const nextMethod = syncIterator.next;
  return {
    async next() {
      // IteratorNext(syncIteratorRecord) - sync call, may throw.
      const iterResult = FunctionPrototypeCall(nextMethod, syncIterator);
      if (type(iterResult) !== "Object") {
        throw new TypeError(
          "The iterator.next() method must return an object",
        );
      }
      if (iterResult.done) {
        return { done: true, value: undefined };
      }
      // 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 };
      }

View on GitHub (pinned to f7822238ca)

Solutions

  1. Always return { done: boolean, value: any } from next()
  2. Finish with { done: true } (value optional) rather than a bare primitive
  3. Replace the custom iterator with a generator (function*) which always produces valid IteratorResults

Example fix

// before
const body = {
  [Symbol.iterator]: () => ({ next: () => 'chunk' }), // returns a string
};

// after
const body = {
  [Symbol.iterator]: () => ({ next: () => ({ done: false, value: 'chunk' }) }),
};
Defensive patterns

Strategy: validation

Validate before calling

const it = body[Symbol.iterator]();
const first = it.next();
if (typeof first !== 'object' || first === null) {
  throw new TypeError('custom iterator next() must return { done, value }');
}

Type guard

const isIteratorResult = (r: unknown): r is IteratorResult<unknown, unknown> =>
  typeof r === 'object' && r !== null;

Prevention

When it happens

Trigger: A hand-rolled sync iterator whose next() returns a primitive, e.g. { next: () => 42 } or { next() { return 'done'; } }, used as an async-iterable input such as fetch(url, { body }); also generators delegating with yield* to a broken inner iterator.

Common situations: Returning the value directly instead of { done, value }; returning true/false for completion; next() returning undefined after exhaustion instead of { done: true }.

Related errors


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