sindresorhus/is · error · TypeError

Expected value which is `AsyncFunction`, received value of t

Error message

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

What it means

Thrown by `assertAsyncFunction(value)` when the value's internal object tag is not `AsyncFunction` — i.e. it was not declared with `async function`/`async () =>`. Crucially, an ordinary function that returns a Promise is NOT an AsyncFunction by this check, since the detection is syntactic (via the object tag), not behavioral.

Source

Thrown at source/index.ts:1462

	}
}

export function assertArrayBuffer(value: unknown, message?: string): asserts value is ArrayBuffer {
	if (!isArrayBuffer(value)) {
		throw new TypeError(message ?? typeErrorMessage('ArrayBuffer', value));
	}
}

export function assertArrayLike<T = unknown>(value: unknown, message?: string): asserts value is ArrayLike<T> {
	if (!isArrayLike(value)) {
		throw new TypeError(message ?? typeErrorMessage('array-like', value));
	}
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
export function assertAsyncFunction(value: unknown, message?: string): asserts value is Function {
	if (!isAsyncFunction(value)) {
		throw new TypeError(message ?? typeErrorMessage('AsyncFunction', value));
	}
}

export function assertAsyncGenerator(value: unknown, message?: string): asserts value is AsyncGenerator {
	if (!isAsyncGenerator(value)) {
		throw new TypeError(message ?? typeErrorMessage('AsyncGenerator', value));
	}
}

export function assertAsyncGeneratorFunction(value: unknown, message?: string): asserts value is AsyncGeneratorFunction {
	if (!isAsyncGeneratorFunction(value)) {
		throw new TypeError(message ?? typeErrorMessage('AsyncGeneratorFunction', value));
	}
}

export function assertAsyncIterable<T = unknown>(value: unknown, message?: string): asserts value is AsyncIterable<T> {
	if (!isAsyncIterable(value)) {
		throw new TypeError(message ?? typeErrorMessage('AsyncIterable', value));

View on GitHub ↗ (pinned to 7821031c66)

Solutions

  1. Declare the callback with the `async` keyword instead of returning a Promise manually.
  2. If promise-returning plain functions should be accepted, assert `assert.function` and check the returned value with `assert.promise` at call time instead.
  3. Raise your compile target to ES2017+ so async functions are emitted natively and keep their tag.
  4. Unwrap mocking-framework wrappers or make the mock implementation itself an async function.

Example fix

// before
registerHandler(() => fetchData()); // plain fn returning Promise, throws
// after
registerHandler(async () => fetchData());
Defensive patterns

Strategy: type-guard

Validate before calling

const AsyncFunction = (async () => {}).constructor;
if (!(fn instanceof AsyncFunction)) { /* handle */ }

Type guard

const isAsyncFunction = (fn) =>
  typeof fn === 'function' && fn.constructor?.name === 'AsyncFunction';

Try / catch

try {
  assert.asyncFunction(fn);
} catch (error) {
  if (error instanceof TypeError) { /* fn is sync or not a function */ }
  else { throw error; }
}

Prevention

When it happens

Trigger: Passing a regular function that returns a Promise (`() => Promise.resolve(x)`), a `.bind()`-wrapped async function in some transpiled environments, a promisified callback function, or a transpiled-to-ES5 async function (Babel/TypeScript targeting older ES downlevels async to a generator/plain function, losing the AsyncFunction tag).

Common situations: Build tooling with `target: es5`/`es2015` in tsconfig or Babel stripping the native async tag, so `assert.asyncFunction` fails in production builds but passes in dev; libraries accepting handlers where users pass promise-returning plain functions; mocks/spies (jest.fn wrapping) that aren't tagged AsyncFunction.

Related errors


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