solidjs/solid · error · TypeError

Expected the observer to be an object.

Error message

Expected the observer to be an object.

What it means

Thrown by observable().subscribe() when the argument is not an object. The observable interop wraps a Solid accessor in an RxJS-style Observable, and the spec requires the observer to be either a function or an object with a next method. Solid validates this up front and throws a TypeError for null, undefined, or primitives.

Source

Thrown at packages/solid/src/reactive/observable.ts:50

      next?: (v: T) => void;
      error?: (v: any) => void;
      complete?: (v: boolean) => void;
    };
/**
 * Creates a simple observable from a signal's accessor to be used with the `from` operator of observable libraries like e.g. rxjs
 * ```typescript
 * import { from } from "rxjs";
 * const [s, set] = createSignal(0);
 * const obsv$ = from(observable(s));
 * obsv$.subscribe((v) => console.log(v));
 * ```
 * description https://docs.solidjs.com/reference/reactive-utilities/observable
 */
export function observable<T>(input: Accessor<T>): Observable<T> {
  return {
    subscribe(observer: ObservableObserver<T>) {
      if (!(observer instanceof Object) || observer == null) {
        throw new TypeError("Expected the observer to be an object.");
      }

      const handler =
        typeof observer === "function" ? observer : observer.next && observer.next.bind(observer);

      if (!handler) {
        return { unsubscribe() {} };
      }

      const dispose = createRoot(disposer => {
        createEffect(() => {
          const v = input();
          untrack(() => handler(v));
        });

        return disposer;
      });

View on GitHub (pinned to f47845f9cc)

Solutions

  1. Pass either a plain function or an object with a next method: subscribe({ next: v => ... })
  2. Default the observer: subscribe(observer || { next: () => {} })
  3. If interoperating with RxJS, pipe the Solid observable into RxJS's from() rather than hand-writing observers

Example fix

// before
const obs = observable(signal);
obs.subscribe(maybeObserver); // maybeObserver is undefined

// after
const obs = observable(signal);
const sub = obs.subscribe(
  maybeObserver ?? { next: (v) => console.log(v) }
);
sub.unsubscribe();
Defensive patterns

Strategy: type-guard

Validate before calling

function isObserver(v: unknown): v is ((v: T) => void) | { next: (v: T) => void } {
  return typeof v === 'function' || (!!v && typeof (v as any).next === 'function');
}
if (!isObserver(observer)) throw new Error('observer must be function or { next }');
observable(accessor).subscribe(observer as any);

Type guard

const isObserver = (v: unknown): v is { next: (v: unknown) => void } | ((v: unknown) => void) =>
  typeof v === 'function' ||
  (v instanceof Object && typeof (v as { next?: unknown }).next === 'function');

Try / catch

try { obs.subscribe(observer); } catch (e) { if (e instanceof TypeError && /observer to be an object/.test(e.message)) fixObserverShape(); else throw e; }

Prevention

When it happens

Trigger: Calling observable(accessor).subscribe(null), subscribe(42), subscribe('x'), or an object without a next method combined with a non-function value; also de-serializing or cloning an observer so it arrives as a primitive.

Common situations: Passing an observer variable that is conditionally undefined; mixing up RxJS subscriber APIs (passing a config object instead of observer); migrating code where a function observer was refactored into an optional object.

Related errors


AI-assisted analysis of solidjs/solid@f47845f9cc (2026-08-27). Data as JSON: /api/errors/0f2ca31f48077946. Report an issue: GitHub.