ReactiveX/rxjs · error · TypeError

${String(value)} is not observable

Error message

${String(value)} is not observable

What it means

Observable.from() first rejects non-objects with this TypeError: only objects (or Observable instances) can be converted. Primitives like numbers, strings, undefined, or symbols fail immediately because none of the conversion paths (asyncIterable, iterable, Observable-like with Symbol.observable, thenable/promise) can apply.

Source

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

            subscriber.error(error);
          }
        },
        (error) => subscriber.error(error)
      );
    };

    pull();
  });
}

class ObservableImpl<T> implements Subscribable<T> {
  static from<T>(value: ObservableValue<T>): Observable<T> {
    if (value instanceof Observable) {
      return value;
    }

    if (!isObject(value)) {
      throw new TypeError(`${String(value)} is not observable`);
    }

    const ObservableCtor = staticCtor<T>(this);
    const asyncIteratorMethod = getMethod(value, Symbol.asyncIterator);
    if (asyncIteratorMethod) {
      return fromAsyncIterable(ObservableCtor, value);
    }

    const iteratorMethod = getMethod(value, Symbol.iterator);
    if (iteratorMethod) {
      return fromIterable(ObservableCtor, value);
    }

    const thenMethod = getMethod(value, 'then');
    if (thenMethod) {
      return new ObservableCtor((subscriber) => {
        Promise.resolve(value as PromiseLike<T>).then(
          (output) => {

View on GitHub (pinned to 54796b38a5)

Solutions

  1. If you want the value as a single emission, wrap it in an array: Observable.from([value]) — or use an of-style creation.
  2. Check that the variable is actually defined at the call site (undefined from a failed import or typo).
  3. If it should be a Promise, use Observable.from(Promise.resolve(value)).
  4. Add a type guard before calling from when input type is unknown.

Example fix

// before
Observable.from(user.id); // number
// after
Observable.from([user.id]); // emits user.id once, then completes
Defensive patterns

Strategy: type-guard

Validate before calling

if (value !== null && (typeof value === 'object' || typeof value === 'function')) { obs = Observable.from(value); } else { obs = Observable.from([value]); }

Type guard

function isObservableCandidate(v: unknown): v is object {
  return v !== null && (typeof v === 'object' || typeof v === 'function');
}

Try / catch

try { obs = Observable.from(input); } catch (e) { if (e instanceof TypeError && /is not observable/.test(e.message)) { obs = Observable.from([input]); } else throw e; }

Prevention

When it happens

Trigger: Observable.from(42), Observable.from('hello'), Observable.from(null), Observable.from(undefined) — any primitive argument.

Common situations: Passing a value that was expected to be an Observable or Promise but is actually undefined due to an import/export mistake or bad destructuring; dynamically-typed data where a field is sometimes a primitive; porting code from a library whose from() accepted single values.

Related errors


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