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

  1. Make [Symbol.asyncIterator]() return an async iterator object — easiest via an async generator: async *[Symbol.asyncIterator]() { ... }.
  2. If delegating, return the other source's iterator: return otherSource[Symbol.asyncIterator]().
  3. Check for a missing return statement in a custom asyncIterator implementation.
  4. 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

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


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