ReactiveX/rxjs · error · TypeError

Iterator next() must return an Object

Error message

Iterator next() must return an Object

What it means

While pulling values from a sync iterable inside fromIterable, each call to iterator.next() must return an object of the shape { done, value }. If a call yields a primitive (or undefined), the polyfill throws this TypeError to enforce the iterator result contract, and the subscriber errors out after closing the iterator.

Source

Thrown at packages/observable-polyfill/src/index.ts:443

    if (!subscriber.active) {
      return;
    }

    let finished = false;
    const closeIterator: Teardown = () => {
      if (!finished) {
        closeSyncIterator(record, subscriber.signal.reason);
      }
    };
    closeIterator[propagateTeardownError] = true;
    subscriber.addTeardown(closeIterator);

    try {
      while (subscriber.active) {
        const result = record.next.call(record.iterator);
        if (!isObject(result)) {
          throw new TypeError('Iterator next() must return an Object');
        }

        const iteratorResult = result as IteratorResult<T>;
        if (iteratorResult.done) {
          finished = true;
          subscriber.complete();
          return;
        }
        subscriber.next(iteratorResult.value);
      }
    } catch (error) {
      subscriber.error(error);
    }
  });
}

function fromAsyncIterable<T>(ObservableCtor: typeof Observable<T>, value: object): Observable<T> {
  return new ObservableCtor((subscriber) => {

View on GitHub (pinned to 54796b38a5)

Solutions

  1. Fix next() to always return an object: { value, done: boolean } including the final { done: true }.
  2. Prefer generators (function*) which produce conforming results automatically.
  3. Audit exhaustion paths — the most common bug is returning undefined when finished.
  4. Validate with a quick loop before passing to from(): for (const _ of iterable) break;

Example fix

// before
next() { return this.i < 3 ? this.values[this.i++] : undefined; }
// after
next() { return this.i < 3 ? { value: this.values[this.i++], done: false } : { value: undefined, done: true }; }
Defensive patterns

Strategy: validation

Validate before calling

const it = iterable[Symbol.iterator]();
const r = it.next();
if (!(r instanceof Object)) throw new Error('iterator next() must return an object');

Type guard

function isValidIteratorResult(r: unknown): r is IteratorResult<unknown> {
  return r instanceof Object;
}

Try / catch

Observable.from(iterable).subscribe({ error: e => { if (e instanceof TypeError && /must return an Object/.test(e.message)) { /* fix iterator */ } } });

Prevention

When it happens

Trigger: Observable.from(customIterable) where the iterator's next() returns undefined, a bare value, or another non-object at some point during iteration (often after exhaustion).

Common situations: Custom iterators that return the value directly instead of { value, done }; state-machine iterators with a missing/typo'd terminal branch (return; instead of return { done: true }); test doubles returning null.

Related errors


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