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
- Always return { done: boolean, value: any } from next()
- Finish with { done: true } (value optional) rather than a bare primitive
- 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
- Prefer generators for custom iterables - they always return valid results
- Type next() as returning IteratorResult<T>
- Unit-test custom iterators: the very first next() call must return an object
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
- The iterator.return() method must return an object
- ${openContext} could not be iterated because iterator method
- ${openContext} failed to iterate next value because the next
- Cannot convert a BigInt value to a number
- Cannot convert a Symbol value to a string
AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20).
Data as JSON: /api/errors/aaadb84effadc4da.
Report an issue: GitHub.