ReactiveX/rxjs · error · TypeError

RxJS Next expand options must be an object.

Error message

RxJS Next expand options must be an object.

What it means

The second parameter of expand in RxJS Next must be an options object (with an optional concurrent number) or undefined. Passing a primitive (number, string, boolean) or null — e.g. the legacy concurrency number — throws this TypeError.

Source

Thrown at packages/rxjs/src/expand.ts:25

  concurrent?: number;
}

declare global {
  interface Observable<T> {
    [expand]<R>(project: (value: T, index: number) => ObservableValue<R>, options?: ExpandOptions): Observable<T | R>;
  }
}

Observable.prototype[expand] = function <T, R>(
  this: Observable<T>,
  project: (value: T, index: number) => ObservableValue<R>,
  options?: ExpandOptions
): Observable<T | R> {
  if (arguments.length > 2) {
    throw new TypeError('RxJS Next expand does not support a scheduler argument.');
  }
  if (options !== undefined && (typeof options !== 'object' || options === null)) {
    throw new TypeError('RxJS Next expand options must be an object.');
  }

  const configuredConcurrency = options?.concurrent ?? Infinity;
  const concurrency = configuredConcurrency >= 1 ? configuredConcurrency : Infinity;

  return this[create]((subscriber) => {
    const queue: Array<T | R> = [];
    let active = 0;
    let index = 0;
    let sourceComplete = false;
    let draining = false;

    const checkComplete = (): void => {
      if (sourceComplete && active === 0 && queue.length === 0 && subscriber.active) {
        subscriber.complete();
      }
    };

View on GitHub (pinned to 54796b38a5)

Solutions

  1. Wrap the concurrency in the options object: expand(project, { concurrent: 5 })
  2. Pass undefined or omit the second argument when no options are needed

Example fix

// before
source[expand](project, 1);
// after
source[expand](project, { concurrent: 1 });
Defensive patterns

Strategy: validation

Validate before calling

if (options !== undefined && (typeof options !== 'object' || options === null)) {
  options = { concurrent: options as number }; // coerce legacy numeric concurrency
}
obs[expand](project, options);

Type guard

const isExpandOptions = (v: unknown): v is { concurrent?: number } =>
  v === undefined || (typeof v === 'object' && v !== null);

Prevention

When it happens

Trigger: observable[expand](project, 5) — RxJS 7 allowed a numeric concurrency as the second argument; also expand(fn, null) or expand(fn, 'x').

Common situations: Migrated RxJS 7 code that passed concurrency positionally: expand(project, 1) for breadth-first traversal limiting.

Related errors


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