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
- Guard subscriptions with an observer factory that always provides next: subscribe(typeof o === 'function' ? o : { next: o?.next ?? (() => {}) })
- Skip subscribing during SSR via isServer and subscribe in onMount/onCleanup
- 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
- Subscribe only on the client (guard with isServer / onMount)
- Always provide a concrete observer object at the call site
- Share one observer factory across isomorphic code
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
- Expected the observer to be an object.
- getContextId cannot be used under non-hydrating context
- getNextContextId cannot be used under non-hydrating context
- Attempting to use server context in non-server build
- Dispose method must be an explicit argument to createRoot fu
AI-assisted analysis of solidjs/solid@f47845f9cc (2026-08-27).
Data as JSON: /api/errors/d3fb32d0d86c4c81.
Report an issue: GitHub.