sindresorhus/is · error · TypeError

Expected value which is `Promise`, received value of type `$

Error message

Expected value which is `Promise`, received value of type `${is(value)}`.

What it means

Thrown by `assert.promise()` when the value is not a Promise. `isPromise` checks for a native Promise or a thenable-shaped object; plain values, resolved results, and functions that return promises (but weren't called) all fail. It narrows to `Promise<T>` so the value can be safely awaited or chained.

Source

Thrown at source/index.ts:1860

		throw new TypeError(message ?? typeErrorMessage('positive integer', value));
	}
}

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

export function assertPrimitive(value: unknown, message?: string): asserts value is Primitive {
	if (!isPrimitive(value)) {
		throw new TypeError(message ?? typeErrorMessage('primitive', value));
	}
}

export function assertPromise<T = unknown>(value: unknown, message?: string): asserts value is Promise<T> {
	if (!isPromise(value)) {
		throw new TypeError(message ?? typeErrorMessage('Promise', value));
	}
}

export function assertPropertyKey(value: unknown, message?: string): asserts value is PropertyKey {
	if (!isPropertyKey(value)) {
		throw new TypeError(message ?? typeErrorMessage('PropertyKey', value));
	}
}

export function assertRegExp(value: unknown, message?: string): asserts value is RegExp {
	if (!isRegExp(value)) {
		throw new TypeError(message ?? typeErrorMessage('RegExp', value));
	}
}

export function assertSafeInteger(value: unknown, message?: string): asserts value is number {
	if (!isSafeInteger(value)) {
		throw new TypeError(message ?? typeErrorMessage('safe integer', value));

View on GitHub ↗ (pinned to 7821031c66)

Solutions

  1. Invoke the async function instead of passing its reference: `assert.promise(fetchData())`, not `assert.promise(fetchData)`.
  2. Remove a premature `await` if the assert is meant to receive the pending promise itself.
  3. If the producer became synchronous, wrap with `Promise.resolve(value)` or update the contract so the assert is no longer needed.
  4. Promisify callback-style APIs with `util.promisify` before asserting.

Example fix

// before
const data = await fetchData();
assert.promise(data); // throws: received the resolved value's type
// after
const pending = fetchData();
assert.promise(pending);
const data = await pending;
Defensive patterns

Strategy: type-guard

Validate before calling

if (value == null || typeof value.then !== 'function') {
  throw new TypeError('Expected a Promise/thenable');
}

Type guard

function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
  return value != null && typeof (value as any).then === 'function';
}

Try / catch

try {
  ow(value, ow.promise);
} catch (error) {
  if (error instanceof ArgumentError) {
    throw new TypeError(`Expected a Promise: ${error.message}`);
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling `assert.promise(value)` with the already-awaited result of a promise, an async function reference that was never invoked (`fn` instead of `fn()`), a synchronous function's return value, or a callback-style API result.

Common situations: Refactoring an async function to synchronous (or vice versa) without updating callers; forgetting the parentheses on an async call; awaiting too early so the assert receives the resolved value; mixing callback and promise APIs (e.g. a library version change from callbacks to promises or back).

Related errors


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