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

  1. 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).
  2. If wrapping another source, delegate: [Symbol.iterator]() { return someRealIterator; }
  3. If you meant to pass a single value, wrap it: Observable.from([value]).
  4. 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

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


AI-assisted analysis of ReactiveX/rxjs@54796b38a5 (2026-08-28). Data as JSON: /api/errors/ff5c3aa41e1f75d4. Report an issue: GitHub.