ReactiveX/rxjs · error · TypeError
Symbol.asyncIterator must return an object
Error message
Symbol.asyncIterator must return an object
What it means
When Observable.from encounters an object with a Symbol.asyncIterator method, it calls that method and requires the result to be an object (the async iterator). If the call returns a primitive (number, string, undefined, etc.), the polyfill throws this TypeError, mirroring the async-iterator record creation step of the async iteration protocol.
Source
Thrown at packages/observable-polyfill/src/index.ts:369
const iterator = iteratorMethod.call(value);
if (!isObject(iterator)) {
throw new TypeError('Symbol.iterator must return an object');
}
const next = getMethod(iterator, 'next');
if (!next) {
throw new TypeError('Iterator must define a callable next() method');
}
return { iterator, next };
}
function getAsyncIteratorRecord(value: object): AsyncIteratorRecord {
const asyncIteratorMethod = getMethod(value, Symbol.asyncIterator);
if (asyncIteratorMethod) {
const iterator = asyncIteratorMethod.call(value);
if (!isObject(iterator)) {
throw new TypeError('Symbol.asyncIterator must return an object');
}
return { iterator };
}
return { iterator: getSyncIteratorRecord(value).iterator };
}
function closeSyncIterator(record: SyncIteratorRecord<unknown>, reason: unknown): void {
const returnMethod = getMethod(record.iterator, 'return');
if (!returnMethod) {
return;
}
const result = returnMethod.call(record.iterator, reason);
if (!isObject(result)) {
throw new TypeError('Iterator return() must return an Object');
}
}View on GitHub (pinned to 54796b38a5)
Solutions
- Make [Symbol.asyncIterator]() return an async iterator object — easiest via an async generator: async *[Symbol.asyncIterator]() { ... }.
- If delegating, return the other source's iterator: return otherSource[Symbol.asyncIterator]().
- Check for a missing return statement in a custom asyncIterator implementation.
- Remove the Symbol.asyncIterator property if the object is meant to be a sync iterable.
Example fix
// before
const bad = { [Symbol.asyncIterator]() { /* forgot return */ } };
Observable.from(bad);
// after
const good = { async *[Symbol.asyncIterator]() { yield 1; } };
Observable.from(good); Defensive patterns
Strategy: validation
Validate before calling
const it = (value as any)[Symbol.asyncIterator]?.();
if (!(it instanceof Object)) throw new Error('asyncIterator must return an object'); Type guard
function isAsyncIterable<T>(v: unknown): v is AsyncIterable<T> {
return !!v && typeof v === 'object' &&
typeof (v as AsyncIterable<T>)[Symbol.asyncIterator] === 'function';
} Try / catch
try { obs = Observable.from(input); } catch (e) { if (e instanceof TypeError && /asyncIterator must return an object/.test(e.message)) { /* skip or replace source */ } else throw e; } Prevention
- Implement async iterables as async generators.
- Delegate [Symbol.asyncIterator] to a real source instead of hand-writing it.
- Unit-test the object returned by [Symbol.asyncIterator].()
When it happens
Trigger: Observable.from(obj) where obj[Symbol.asyncIterator] exists but returns a non-object (e.g. returns undefined because the method lacks a return statement, or returns a Promise or primitive).
Common situations: Async generator mocks in tests; objects that declare [Symbol.asyncIterator] but implement it incorrectly; accidental early return in a hand-rolled async iterator; Node streams/web streams wrappers that return the wrong handle.
Related errors
- Iterator must define a callable next() method
- Iterator next() must return an Object
- ${String(value)} is not observable
- Migration result was refused for source: ${sourcePath}
- ${message}
AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28).
Data as JSON: /api/errors/004cff1b803684c5.
Report an issue: GitHub.