solidjs/solid · error · TypeError

Expected the observer to be an object.

Error message

Expected the observer to be an object.

What it means

Server-side twin of the client observable: on the server, observable(accessor).subscribe() still validates that the observer is a function or object with next. Server observables only emit the current value and complete immediately, but the observer contract is identical, and invalid observers throw the same TypeError.

Source

Thrown at packages/solid/src/server/reactive.ts:312

  let s: U[] = [];
  if (items && items.length) {
    for (let i = 0, len = items.length; i < len; i++) s.push(mapFn(() => items[i], i));
  } else if (options.fallback) s = [options.fallback()];
  return () => s;
}

export type ObservableObserver<T> =
  | ((v: T) => void)
  | {
      next: (v: T) => void;
      error?: (v: any) => void;
      complete?: (v: boolean) => void;
    };
export function observable<T>(input: Accessor<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. Guard subscriptions with an observer factory that always provides next: subscribe(typeof o === 'function' ? o : { next: o?.next ?? (() => {}) })
  2. Skip subscribing during SSR via isServer and subscribe in onMount/onCleanup
  3. Verify the observer value is defined before subscribing

Example fix

// before
const sub = observable(accessor).subscribe(observer); // observer undefined on server

// after
import { isServer } from 'solid-js/web';
if (!isServer) {
  const sub = observable(accessor).subscribe(
    typeof observer === 'function' ? observer : { next: observer.next.bind(observer) }
  );
  onCleanup(() => sub.unsubscribe());
}
Defensive patterns

Strategy: type-guard

Validate before calling

import { isServer } from 'solid-js/web';
if (!isServer && isObserver(observer)) obs.subscribe(observer);

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Using observable() during SSR/streaming rendering and passing null, a primitive, or an object lacking next to subscribe; shared code paths that run both client and server hitting different observer shapes.

Common situations: Isomorphic utilities subscribing during SSR; hydrating an app where a client-only observer is undefined on the server; testing SSR output with mocked observers.

Related errors


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