jestjs/jest · error · JestAssertionError
received value must be a promise or a function returning a p
Error message
received value must be a promise or a function returning a promise
What it means
expect(x).resolves.<matcher>() wraps the actual value (or calls it if a function) and checks isPromise. If the value is not a Promise (and calling it didn't return one), it throws a JestAssertionError with a matcherHint header. .resolves only makes sense for promises; using it on a sync value is a misuse the library refuses to silently await.
Source
Thrown at packages/expect/src/index.ts:181
const makeResolveMatcher =
(
matcherName: string,
matcher: RawMatcherFn,
isNot: boolean,
actual: Promise<any> | (() => Promise<any>),
outerErr: JestAssertionError,
): PromiseMatcherFn =>
(...args) => {
const options = {
isNot,
promise: 'resolves',
};
const actualWrapper: Promise<any> =
typeof actual === 'function' ? actual() : actual;
if (!isPromise(actualWrapper)) {
throw new JestAssertionError(
matcherUtils.matcherErrorMessage(
matcherUtils.matcherHint(matcherName, undefined, '', options),
`${matcherUtils.RECEIVED_COLOR(
'received',
)} value must be a promise or a function returning a promise`,
matcherUtils.printWithType(
'Received',
actual,
matcherUtils.printReceived,
),
),
);
}
const innerErr = new JestAssertionError();
return actualWrapper.then(
result =>View on GitHub (pinned to f49721c78e)
Solutions
- Use plain expect for synchronous values: expect(value).toBe(5).
- Ensure the value is actually a Promise: expect(asyncFn()).resolves.toBe(5) — call the async function so it returns a promise.
- Add `await` where needed so you pass the unwrapped value to a sync matcher, or keep .resolves and pass the promise itself.
Example fix
// before
function getAnswer() { return 42; }
expect(getAnswer()).resolves.toBe(42); // not a promise
// after — sync matcher
expect(getAnswer()).toBe(42);
// or, if it should be async:
async function getAnswer() { return 42; }
expect(getAnswer()).resolves.toBe(42); Defensive patterns
Strategy: type-guard
Validate before calling
const value = typeof actual === 'function' ? actual() : actual;
if (!isPromise(value)) {
throw new TypeError('use plain expect() for non-promise values');
}
// now safe to use .resolves Type guard
function isThenable(x: unknown): x is Promise<unknown> {
return !!x && typeof (x as any).then === 'function';
} Try / catch
// .resolves throws synchronously before returning the chained matcher — convert to a sync matcher or fix the source
Prevention
- Use .resolves only on values that are actually promises.
- For sync values use plain expect(actual).toBe(...).
- Double-check that async functions are invoked so they return a promise.
When it happens
Trigger: Calling expect(5).resolves.toBe(5), expect('foo').resolves.toEqual('foo'), expect(() => 42).resolves.toBe(42) (function returns a non-promise), or expect(maybePromise).resolves... where maybePromise resolved to a non-promise value.
Common situations: Forgetting to await the function before expect; testing a sync function with .resolves; refactoring an async function to sync without removing .resolves; double-awaiting.
Related errors
- Expect takes at most one argument.
- received value must be a number
- received value must be a non-null object
- received value must be a function
- Jest: concurrent test "${specFullName}" must return a Promis
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/852eef1578891dc3.json.
Report an issue: GitHub.