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.

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.

Appendix: 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)