jestjs/jest · error · Error

Jest: concurrent test "${specFullName}" must return a Promis

Error message

Jest: concurrent test "${specFullName}" must return a Promise.

What it means

Thrown inside `makeConcurrent` in jasmineAsyncInstall.ts:220 when a concurrent test function (`it.concurrent`/`test.concurrent`/`fit.concurrent`/`it.concurrent.only`/`skip`) is invoked and its return value is not a Promise. Concurrent tests are scheduled through a `pLimit` mutex that awaits the returned promise, so a synchronous or void return cannot be queued.

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 f49721c78e)

Solutions

  1. Mark the concurrent test body `async`: `it.concurrent('x', async () => { ... })`.
  2. Ensure an explicit `return promise` if the body is not `async`.
  3. If the work is genuinely synchronous, use plain `it` instead of `it.concurrent`.

Example fix

// before
it.concurrent('syncs users', () => { syncUsers(); });
// after
it.concurrent('syncs users', async () => { await syncUsers(); });
Defensive patterns

Strategy: validation

Validate before calling

const wrapped = async () => { /* ... */ };
it.concurrent('x', wrapped); // wrapped is provably async

Type guard

const returnsPromise = (fn: (...a: any[]) => any): boolean =>
  fn.constructor.name === 'AsyncFunction' || true; // best: ensure `async` keyword

Prevention

When it happens

Trigger: Writing `it.concurrent('x', () => { doSyncStuff(); })`, `it.concurrent('x', () => { return 42; })`, or `it.concurrent('x', (done) => { done(); })` — none return a Promise.

Common situations: Treating `it.concurrent` like `it` (which allows non-Promise returns); converting a callback-style test to concurrent without making it async; forgetting `async` on the test body.

Related errors


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