jestjs/jest · error · Error
Jest: concurrent test "${spec.getFullName()}" must return a
Error message
Jest: concurrent test "${spec.getFullName()}" must return a Promise. What it means
Thrown by the concurrent test wrapper in jest-jasmine2 (jasmineAsyncInstall.ts:220) when the body of a concurrent test (it.concurrent / test.concurrent) does not return a Promise. Concurrent tests run through a mutex that awaits the returned value, so a synchronous return is treated as a programming error.
Source
Thrown at packages/jest-jasmine2/src/jasmineAsyncInstall.ts:220
const concurrentFn = function (
specName: Global.TestNameLike,
fn: Global.ConcurrentTestFn,
timeout?: number,
) {
let promise: Promise<unknown> = Promise.resolve();
const spec = originalFn.call(env, specName, () => promise, timeout);
if (env != null && !env.specFilter(spec)) {
return spec;
}
try {
promise = mutex(() => {
const promise = fn();
if (isPromise(promise)) {
return promise;
}
throw new Error(
`Jest: concurrent test "${spec.getFullName()}" must return a Promise.`,
);
});
} catch (error) {
promise = Promise.reject(error);
}
// Avoid triggering the uncaught promise rejection handler in case the test errors before
// being awaited on.
// eslint-disable-next-line @typescript-eslint/no-empty-function
promise.catch(() => {});
return spec;
};
// eslint-disable-next-line unicorn/consistent-function-scoping
const failing = () => {
throw new Error(
'Jest: `failing` tests are only supported in `jest-circus`.',View on GitHub (pinned to 8e6d128e4a)
Solutions
- Make the body async and return/await: test.concurrent('x', async () => { await doAsyncWork(); }).
- If the work is genuinely synchronous, use plain test()/it() instead of test.concurrent().
- Replace jest done-callback style with promise-returning async functions when using concurrent.
- Add a lint rule banning test.concurrent bodies that are not async functions.
Example fix
// before
test.concurrent('sync', () => { compute(); });
// after
test.concurrent('async', async () => { await computeAsync(); }); Defensive patterns
Strategy: type-guard
Validate before calling
const body = () => doWork();
if (!body.toString().includes('async') && typeof body() !== 'object') {
// sanity check; better to just always use async
}
test.concurrent('x', async () => { await doWork(); }); Type guard
const returnsPromise = (fn: (...a: any[]) => unknown): fn is (...a: any[]) => Promise<unknown> => fn.constructor.name === 'AsyncFunction';
Prevention
- Always make concurrent test bodies async.
- Avoid the done-callback style under concurrent mode.
- Use plain test() for synchronous work.
When it happens
Trigger: test.concurrent('x', () => { doSyncWork(); }) with no async/return, test.concurrent('x', (done) => { done(); }) using the legacy done callback instead of returning a promise, or test.concurrent('x', () => someSyncResult) where the function returns a plain value.
Common situations: Converting a sync test to concurrent without making it async; mixing jest done-style callbacks with concurrent mode; returning undefined from an arrow function whose body is a block; bumping Jest versions where concurrent semantics tightened.
Related errors
- received value must be a promise or a function returning a p
- describe does not expect any arguments
- <spyOn> : could not find an object to spy upon for ${methodN
- <spyOn> : No method name supplied Usage: spyOn(<object>, <me
- <spyOn> : ${methodName}() method does not exist Usage: spyOn
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/c2c4ec58586aa014.
Report an issue: GitHub.