{"record":{"id":"121af9ea80016bdf","repo":"facebook/relay","slug":"observer-must-be-an-object-with-callbacks-strin","errorCode":null,"errorMessage":"Observer must be an Object with callbacks: ${String(observer)}","messagePattern":"Observer must be an Object with callbacks: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/relay-runtime/network/RelayObservable.js","lineNumber":323,"sourceCode":"        current = subscription;\n      }\n      return () => {\n        current && current.unsubscribe();\n      };\n    });\n  }\n\n  /**\n   * Observable's primary API: returns an unsubscribable Subscription to the\n   * source of this Observable.\n   *\n   * Note: A sink may be passed directly to .subscribe() as its observer,\n   * allowing for easily composing Observables.\n   */\n  subscribe(observer: Observer<T> | Sink<T>): Subscription {\n    if (__DEV__) {\n      // Early runtime errors for ill-formed observers.\n      if (!observer || typeof observer !== 'object') {\n        throw new Error(\n          'Observer must be an Object with callbacks: ' + String(observer),\n        );\n      }\n    }\n    return subscribe(this._source, observer);\n  }\n\n  /**\n   * Returns a new Observerable where each value has been transformed by\n   * the mapping function.\n   */\n  map<U>(fn: T => U): RelayObservable<U> {\n    return RelayObservable.create(sink => {\n      const subscription = this.subscribe({\n        complete: sink.complete,\n        error: sink.error,\n        next: value => {","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/relay-runtime/network/RelayObservable.js#L305-L341","documentation":"`subscribe()` must receive an observer — an object with callbacks such as `next`, `error`, `complete` (or a sink). This dev-mode check throws when subscribing with a non-object (e.g. a bare function or undefined). Unlike some libraries, RelayObservable does not accept a bare callback function as shorthand for `{next: fn}`.","triggerScenarios":"`observable.subscribe(fn)` passing a function instead of `{next: fn}`; `observable.subscribe()` with no argument; subscribing with a primitive.","commonSituations":"Migrating from RxJS-style `subscribe(callback)` shorthand; forgetting the observer entirely; destructuring mistakes that lose the object.","solutions":["Pass an object: `observable.subscribe({next: value => ...})`","If you have a bare callback, wrap it as `{next: callback}`","Include `error` and `complete` handlers in the observer object to avoid swallowed errors"],"exampleFix":"// before\nobservable.subscribe(value => console.log(value));\n// after\nobservable.subscribe({\n  next: value => console.log(value),\n  error: err => console.error(err),\n  complete: () => console.log('done'),\n});","handlingStrategy":"type-guard","validationCode":"function safeSubscribe(obs, observer) {\n  if (observer == null || typeof observer !== 'object') {\n    throw new TypeError('subscribe requires an observer object like {next, error, complete}');\n  }\n  return obs.subscribe(observer);\n}","typeGuard":"function isObserver(o: unknown): o is {next?: (v: unknown) => void; error?: (e: unknown) => void; complete?: () => void} {\n  return typeof o === 'object' && o !== null;\n}","tryCatchPattern":"try {\n  observable.subscribe(observer);\n} catch (e) {\n  if (e.message.startsWith('Observer must be an Object')) {\n    if (typeof observer === 'function') observable.subscribe({next: observer});\n    else throw new TypeError('Provide an observer object: {next, error, complete}', {cause: e});\n  } else throw e;\n}","preventionTips":["Always pass an object literal {next, error, complete} to subscribe — no bare-function shorthand like RxJS","Never call subscribe() with no arguments","Include an error handler so errors aren't swallowed","Add a lint rule or code-review check for subscribe(callback) patterns after migrating from RxJS"],"tags":["relay","observable","observer","dev-mode"],"backgroundTag":"invalid-observable-observer","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}