jestjs/jest · error · Error

received value must be a function

Error message

received value must be a function

What it means

Thrown by `toThrow` / `toThrowError` (toThrowMatchers.ts:78, via `createMatcher`) when the value passed to `expect(...)` is not a function and the matcher was not invoked through `.rejects` (the `fromPromise` path). `toThrow` works by calling `received()` inside a try/catch to capture the thrown error; a non-function received cannot be invoked. The check is gated by `!fromPromise`, so `expect(promise).rejects.toThrow()` does not hit this — only the synchronous misuse does.

Source

Thrown at packages/expect/src/toThrowMatchers.ts:102

      isNot: this.isNot,
      promise: this.promise,
    };

    let thrown = null;

    if (fromPromise && isError(received)) {
      thrown = getThrown(received);
    } else {
      if (typeof received === 'function') {
        try {
          received();
        } catch (error) {
          thrown = getThrown(error);
        }
      } else {
        if (!fromPromise) {
          const placeholder = expected === undefined ? '' : 'expected';
          throw new Error(
            matcherErrorMessage(
              matcherHint(matcherName, undefined, placeholder, options),
              `${RECEIVED_COLOR('received')} value must be a function`,
              printWithType('Received', received, printReceived),
            ),
          );
        }
      }
    }

    if (expected === undefined) {
      return toThrow(matcherName, options, thrown);
    } else if (typeof expected === 'function') {
      return toThrowExpectedClass(matcherName, options, thrown, expected);
    } else if (typeof expected === 'string') {
      return toThrowExpectedString(matcherName, options, thrown, expected);
    } else if (expected !== null && typeof expected.test === 'function') {
      return toThrowExpectedRegExp(matcherName, options, thrown, expected);

View on GitHub (pinned to f49721c78e)

Solutions

  1. Pass the function reference, not its result: `expect(fn).toThrow()` (no parens on `fn`).
  2. For async rejections, use `expect(promise).rejects.toThrow()`.
  3. Wrap an inline expression in an arrow function: `expect(() => parse(bad)).toThrow()`.
  4. If you already have the error, assert on it directly with `expect(err.message).toBe(...)` rather than `toThrow`.

Example fix

// before
expect(validate(input)).toThrow(); // validate runs before toThrow

// after
expect(() => validate(input)).toThrow();
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof received !== 'function') {
  throw new Error(`received must be a function for toThrow, got ${typeof received}`);
}
expect(received).toThrow();

Type guard

const isFunction = (v: unknown): v is (...args: any[]) => any =>
  typeof v === 'function';

Try / catch

try {
  expect(received).toThrow();
} catch (e) {
  if (e instanceof Error && /received value must be a function/.test(e.message)) {
    console.error('pass the function reference, not its result (drop the parens)');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `expect(value).toThrow()` where `value` is a string, number, object, undefined, null, or the result of calling a function (instead of the function reference itself). Common: `expect(fn()).toThrow()` — the parens invoke `fn` before `toThrow` can wrap it, so `received` is the return value, not the function. Also `expect(asyncFn()).toThrow()` on a non-awaited async call (should use `.rejects.toThrow()`).

Common situations: Adding parentheses by accident (`expect(fn())` instead of `expect(fn)`); forgetting `.rejects` for async-rejection assertions; passing an error instance directly instead of a throwing function; refactoring from a try/catch test style.

Related errors


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/82e8e13ea496a564.json. Report an issue: GitHub.