jestjs/jest · error · Error

${RECEIVED_COLOR('received')} value must be a function

Error message

${RECEIVED_COLOR('received')} value must be a function

What it means

Thrown by the `toThrow` matcher factory (toThrowMatchers.ts:102) when, in the synchronous (non-promise) path, the received value is not a function. `toThrow` invokes `received()` inside a try/catch to capture a thrown error, so it requires a callable. The guard is skipped only when `fromPromise` is true (i.e. `.rejects.toThrow()`), where received is already the rejection reason.

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 8e6d128e4a)

Solutions

  1. Pass the function reference, not its result: expect(fn).toThrow(), not expect(fn()).toThrow().
  2. For async rejections, use await expect(promise).rejects.toThrow() so the promise path is taken.
  3. If the value is genuinely not a function, use a different matcher (toBeInstanceOf, toEqual) for it.
  4. Wrap an inline throw in an arrow function: expect(() => { throw new Error() }).toThrow().

Example fix

// before
expect(throwIfBad(input)).toThrow();  // invokes eagerly, no fn
expect(badValue).toThrow();            // badValue is not callable

// after
expect(() => throwIfBad(input)).toThrow();
expect(throwIfBad).toThrow();
// async
await expect(promise).rejects.toThrow();
Defensive patterns

Strategy: type-guard

Validate before calling

const v = received;
if (typeof v !== 'function') {
  throw new Error('toThrow requires a function reference, not its result');
}
expect(v).toThrow();
// for async: await expect(promise).rejects.toThrow();

Type guard

const isFunction = (v: unknown): v is Function =>
  typeof v === 'function';

Try / catch

// wrap inline behaviour in an arrow fn
expect(() => {
  throwIfBad(input);
}).toThrow();

Prevention

When it happens

Trigger: Calling `expect(value).toThrow()` where `value` is a number, string, object, null, undefined, or the result of calling a function (instead of the function itself). The most common mistake is invoking the function (`expect(fn()).toThrow()`) so received is the return value, not the function.

Common situations: Passing `fn()` instead of `fn` (eager invocation) — the error throws before expect can catch it, or a non-error return reaches the matcher; passing a value you expected to be a function; forgetting to use `.rejects` for async rejections (then a Promise is received synchronously).

Related errors


AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10). Data as JSON: /api/errors/d53ec3b479218886. Report an issue: GitHub.