ReactiveX/rxjs · error · TypeError
Iterator must define a callable next() method
Error message
Iterator must define a callable next() method
What it means
This error is thrown by the iterator-record helper in @rxjs/observable-polyfill when converting a sync iterable (e.g. in Observable.from or fromIterable). After calling Symbol.iterator on the input, the returned iterator object must expose a callable next method; if getMethod(iterator, 'next') finds nothing (missing or non-function), the polyfill refuses to proceed per the observable-from-iterator protocol.
Source
Thrown at packages/observable-polyfill/src/index.ts:359
throw new TypeError(`${String(key)} must be callable`);
}
return method as Callable;
}
function getSyncIteratorRecord<T>(value: object): SyncIteratorRecord<T> {
const iteratorMethod = getMethod(value, Symbol.iterator);
if (!iteratorMethod) {
throw new TypeError('Object does not define a callable Symbol.iterator method');
}
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 {View on GitHub (pinned to 54796b38a5)
Solutions
- Fix the iterable so its [Symbol.iterator]() returns an iterator object with a callable next() method (e.g. delegate to an array or a generator function).
- If wrapping another source, delegate: [Symbol.iterator]() { return someRealIterator; }
- If you meant to pass a single value, wrap it: Observable.from([value]).
- Validate the input before calling from() using typeof it[Symbol.iterator]?.().next === 'function'.
Example fix
// before
const bad = { [Symbol.iterator]() { return {}; } };
Observable.from(bad);
// after
const good = { *[Symbol.iterator]() { yield 1; yield 2; } };
Observable.from(good); Defensive patterns
Strategy: validation
Validate before calling
function isIterableObj(v: unknown): boolean {
if (!(v instanceof Object) || v === null) return false;
const it = (v as any)[Symbol.iterator]?.();
return it instanceof Object && typeof (it as any)?.next === 'function';
} Type guard
function isSyncIterable<T>(v: unknown): v is Iterable<T> {
return !!v && typeof v === 'object' &&
typeof (v as Iterable<T>)[Symbol.iterator] === 'function';
} Try / catch
try { obs = Observable.from(input); } catch (e) { if (e instanceof TypeError && /callable next/.test(e.message)) { /* fix or replace source */ } else throw e; } Prevention
- Always create iterables with generators or delegate to built-in iterables.
- Validate unknown inputs with isSyncIterable before from().
- Add subscribe-time tests for custom iterables.
When it happens
Trigger: Passing to Observable.from() an object whose Symbol.iterator returns an object without a next() method (or with next set to a non-function value). Also hit when getAsyncIteratorRecord falls back to the sync path for an object with no Symbol.asyncIterator whose Symbol.iterator is malformed.
Common situations: Custom iterable implementations that forget next(); objects that monkey-patch Symbol.iterator to return arbitrary state objects; arrays mutated to delete Array.prototype.next-like helpers; mocks/stubs in tests returning {} from [Symbol.iterator]().
Related errors
- Symbol.asyncIterator must return an object
- Iterator next() must return an Object
- Iterator return() must return an Object
- ${String(value)} is not observable
- Migration result was refused for source: ${sourcePath}
AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28).
Data as JSON: /api/errors/ff5c3aa41e1f75d4.
Report an issue: GitHub.