{"record":{"id":"d3fb32d0d86c4c81","repo":"solidjs/solid","slug":"expected-the-observer-to-be-an-object-d3fb32","errorCode":null,"errorMessage":"Expected the observer to be an object.","messagePattern":"Expected the observer to be an object\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/solid/src/server/reactive.ts","lineNumber":312,"sourceCode":"  let s: U[] = [];\n  if (items && items.length) {\n    for (let i = 0, len = items.length; i < len; i++) s.push(mapFn(() => items[i], i));\n  } else if (options.fallback) s = [options.fallback()];\n  return () => s;\n}\n\nexport type ObservableObserver<T> =\n  | ((v: T) => void)\n  | {\n      next: (v: T) => void;\n      error?: (v: any) => void;\n      complete?: (v: boolean) => void;\n    };\nexport function observable<T>(input: Accessor<T>) {\n  return {\n    subscribe(observer: ObservableObserver<T>) {\n      if (!(observer instanceof Object) || observer == null) {\n        throw new TypeError(\"Expected the observer to be an object.\");\n      }\n\n      const handler =\n        typeof observer === \"function\" ? observer : observer.next && observer.next.bind(observer);\n\n      if (!handler) {\n        return { unsubscribe() {} };\n      }\n\n      const dispose = createRoot(disposer => {\n        createEffect(() => {\n          const v = input();\n          untrack(() => handler(v));\n        });\n\n        return disposer;\n      });\n","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/solidjs/solid/blob/f47845f9cc16ecbb316aa6560c7161f45af9a3d8/packages/solid/src/server/reactive.ts#L294-L330","documentation":"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.","triggerScenarios":"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.","commonSituations":"Isomorphic utilities subscribing during SSR; hydrating an app where a client-only observer is undefined on the server; testing SSR output with mocked observers.","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"],"exampleFix":"// before\nconst sub = observable(accessor).subscribe(observer); // observer undefined on server\n\n// after\nimport { isServer } from 'solid-js/web';\nif (!isServer) {\n  const sub = observable(accessor).subscribe(\n    typeof observer === 'function' ? observer : { next: observer.next.bind(observer) }\n  );\n  onCleanup(() => sub.unsubscribe());\n}","handlingStrategy":"type-guard","validationCode":"import { isServer } from 'solid-js/web';\nif (!isServer && isObserver(observer)) obs.subscribe(observer);","typeGuard":"const isObserver = (v: unknown): v is ((v: unknown) => void) | { next(v: unknown): void } =>\n  typeof v === 'function' || (!!v && typeof (v as any).next === 'function');","tryCatchPattern":"try { obs.subscribe(observer); } catch (e) { if (e instanceof TypeError && /observer to be an object/.test(e.message)) observer = { next: () => {} }; else throw e; }","preventionTips":["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"],"tags":["solid","ssr","observable","typeerror"],"backgroundTag":"invalid-observer-argument","analyzedSha":"f47845f9cc16ecbb316aa6560c7161f45af9a3d8","analyzedAt":"2026-08-27T05:39:24.283Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}