sindresorhus/is · error · TypeError
Expected value which is `Observable`, received value of type
Error message
Expected value which is `Observable`, received value of type `${is(value)}`. What it means
Thrown by `assert.observable()` when the value does not conform to the Observable contract — `isObservable` checks for the `Symbol.observable` (or `@@observable`) interop point per the TC39 Observable proposal. It narrows to `ObservableLike` so code can safely subscribe.
Source
Thrown at source/index.ts:1824
}
}
export function assertNumericString(value: unknown, message?: string): asserts value is `${number}` {
if (!isNumericString(value)) {
throw new TypeError(message ?? typeErrorMessage('string with a number', value));
}
}
// eslint-disable-next-line @typescript-eslint/no-restricted-types
export function assertObject(value: unknown, message?: string): asserts value is object {
if (!isObject(value)) {
throw new TypeError(message ?? typeErrorMessage('Object', value));
}
}
export function assertObservable(value: unknown, message?: string): asserts value is ObservableLike {
if (!isObservable(value)) {
throw new TypeError(message ?? typeErrorMessage('Observable', value));
}
}
export function assertOddInteger(value: number, message?: string): asserts value is number {
if (!isOddInteger(value)) {
throw new TypeError(message ?? typeErrorMessage('odd integer', value));
}
}
export function assertPlainObject<Value = unknown>(value: unknown, message?: string): asserts value is Record<PropertyKey, Value> {
if (!isPlainObject(value)) {
throw new TypeError(message ?? typeErrorMessage('plain object', value));
}
}
export function assertPositiveInteger(value: unknown, message?: string): asserts value is number {
if (!isPositiveInteger(value)) {
throw new TypeError(message ?? typeErrorMessage('positive integer', value));View on GitHub ↗ (pinned to 7821031c66)
Solutions
- Verify the value comes from a library implementing `Symbol.observable` (RxJS does); convert Promises with `from(promise)` (RxJS) first.
- Deduplicate rxjs in your lockfile (`npm dedupe` / resolutions) so all code shares one Symbol.observable registration.
- If the source only exposes `subscribe`, wrap it: `new Observable(sub => source.subscribe(sub))`.
- Import `symbol-observable` polyfill early if targeting environments without the symbol.
Example fix
// before
assert.observable(somePromise); // throws: received 'Promise'
// after
import {from} from 'rxjs';
const obs = from(somePromise);
assert.observable(obs); Defensive patterns
Strategy: type-guard
Validate before calling
if (value == null || typeof value.subscribe !== 'function') {
throw new TypeError('Expected an Observable (object with subscribe and Symbol.observable)');
} Type guard
function isObservable(value: unknown): value is {subscribe: Function} {
return value != null &&
typeof (value as any).subscribe === 'function' &&
typeof (value as any)[Symbol.observable ?? '@@observable'] === 'function';
} Try / catch
try {
ow(value, ow.observable);
} catch (error) {
if (error instanceof ArgumentError) {
throw new TypeError(`Expected an Observable stream: ${error.message}`);
}
throw error;
} Prevention
- Don't pass a Promise where an Observable is expected — convert with rxjs from(promise)
- Observable detection uses Symbol.observable — ensure your Observable implementation defines it (RxJS does)
- Mixing RxJS versions or multiple rxjs copies can break interop; deduplicate the dependency
- Wrap plain values with of(value) before passing to Observable-expecting APIs
When it happens
Trigger: Calling `assert.observable(value)` with a Promise, an RxJS Subject that lost its symbol through serialization, a plain object with only a `subscribe` method but no `Symbol.observable`, or an observable from a library/version that doesn't implement the interop symbol.
Common situations: Mixing RxJS versions in one dependency tree (two rxjs copies, each with its own symbol polyfill); passing a Promise where an Observable is expected; using a lightweight event-emitter that doesn't implement `Symbol.observable`; missing `symbol-observable` polyfill in older environments.
Related errors
- Expected value which is `non-empty array`, received value of
- Expected value which is `non-empty map`, received value of t
- Expected value which is `non-empty object`, received value o
- Expected value which is `non-empty set`, received value of t
- Expected value which is `non-empty string`, received value o
AI-assisted analysis of sindresorhus/is@7821031c66 (2026-07-31).
Data as JSON: /data/errors/c7a1540c96bdc8fe.json.
Report an issue: GitHub ↗.