sindresorhus/is · error · TypeError

Expected value which is `Node.js Stream`, received value of

Error message

Expected value which is `Node.js Stream`, received value of type `${is(value)}`.

What it means

Thrown by `assertNodeStream()` (source/index.ts:1735) when `isNodeStream()` fails; that predicate duck-types the value as `isObject(value) && isFunction(value.pipe) && !isObservable(value)`. So it needs an object with a callable `pipe` method that is not an Observable — it does not require inheriting from Node's stream classes.

Source

Thrown at source/index.ts:1737

		throw new TypeError(message ?? typeErrorMessage('native Promise', value));
	}
}

export function assertNegativeInteger(value: unknown, message?: string): asserts value is number {
	if (!isNegativeInteger(value)) {
		throw new TypeError(message ?? typeErrorMessage('negative integer', value));
	}
}

export function assertNegativeNumber(value: unknown, message?: string): asserts value is number {
	if (!isNegativeNumber(value)) {
		throw new TypeError(message ?? typeErrorMessage('negative number', value));
	}
}

export function assertNodeStream(value: unknown, message?: string): asserts value is NodeStream {
	if (!isNodeStream(value)) {
		throw new TypeError(message ?? typeErrorMessage('Node.js Stream', value));
	}
}

export function assertNonEmptyArray<T = unknown, Item = unknown>(value: T | Item[], message?: string): asserts value is [Item, ...Item[]] {
	if (!isNonEmptyArray(value)) {
		throw new TypeError(message ?? typeErrorMessage('non-empty array', value));
	}
}

export function assertNonEmptyMap<Key = unknown, Value = unknown>(value: unknown, message?: string): asserts value is Map<Key, Value> {
	if (!isNonEmptyMap(value)) {
		throw new TypeError(message ?? typeErrorMessage('non-empty map', value));
	}
}

export function assertNonEmptyObject<Key extends keyof any = string, Value = unknown>(value: unknown, message?: string): asserts value is Record<Key, Value> {
	if (!isNonEmptyObject(value)) {
		throw new TypeError(message ?? typeErrorMessage('non-empty object', value));

View on GitHub ↗ (pinned to 7821031c66)

Solutions

  1. Convert web streams: `stream.Readable.fromWeb(webStream)` (Node 17+) before asserting.
  2. Create a stream from in-memory data: `stream.Readable.from(bufferOrIterable)`.
  3. For RxJS Observables, this assert rejects them by design — convert or use an Observable-aware path instead.
  4. Verify the producer actually returned a stream (not undefined from an error path) before the assert site.

Example fix

// before
const body = (await fetch(url)).body;
assertNodeStream(body); // throws — WHATWG ReadableStream
// after
import {Readable} from 'node:stream';
const body = Readable.fromWeb((await fetch(url)).body);
assertNodeStream(body);
Defensive patterns

Strategy: type-guard

Validate before calling

const {Stream} = require('node:stream');
if (!(value instanceof Stream) && !(value && typeof value.pipe === 'function')) {
  throw new TypeError('Expected a Node.js Stream');
}

Type guard

const isNodeStream = (v: unknown): v is NodeJS.ReadableStream | NodeJS.WritableStream => v !== null && typeof v === 'object' && typeof (v as any).pipe === 'function';

Prevention

When it happens

Trigger: Calling `assertNodeStream()` with a WHATWG web stream (ReadableStream — has `pipeTo`/`pipeThrough`, not `pipe`), a Buffer or string of the full content, an RxJS Observable (explicitly excluded even if it has pipe), an async iterator, or a closed/undefined stream variable.

Common situations: The fetch-API migration is the big one: `fetch()` response bodies and many modern APIs (undici, Node 18+ `fs.openAsBlob`, web streams) return WHATWG streams, not Node streams. Also passing RxJS Observables (whose `.pipe` exists but is deliberately rejected), or file contents read eagerly instead of streamed.

Related errors


AI-assisted analysis of sindresorhus/is@7821031c66 (2026-07-31). Data as JSON: /data/errors/bd1c2d8a7373d3b7.json. Report an issue: GitHub ↗.