{"id":"1c4f480948c1cd19","repo":"jestjs/jest","slug":"jest-concurrent-test-specfullname-must-retur","errorCode":null,"errorMessage":"Jest: concurrent test \"${specFullName}\" must return a Promise.","messagePattern":"Jest: concurrent test \"(.+?)\" must return a Promise\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-jasmine2/src/jasmineAsyncInstall.ts","lineNumber":220,"sourceCode":"  const concurrentFn = function (\n    specName: Global.TestNameLike,\n    fn: Global.ConcurrentTestFn,\n    timeout?: number,\n  ) {\n    let promise: Promise<unknown> = Promise.resolve();\n\n    const spec = originalFn.call(env, specName, () => promise, timeout);\n    if (env != null && !env.specFilter(spec)) {\n      return spec;\n    }\n\n    try {\n      promise = mutex(() => {\n        const promise = fn();\n        if (isPromise(promise)) {\n          return promise;\n        }\n        throw new Error(\n          `Jest: concurrent test \"${spec.getFullName()}\" must return a Promise.`,\n        );\n      });\n    } catch (error) {\n      promise = Promise.reject(error);\n    }\n    // Avoid triggering the uncaught promise rejection handler in case the test errors before\n    // being awaited on.\n    // eslint-disable-next-line @typescript-eslint/no-empty-function\n    promise.catch(() => {});\n\n    return spec;\n  };\n\n  // eslint-disable-next-line unicorn/consistent-function-scoping\n  const failing = () => {\n    throw new Error(\n      'Jest: `failing` tests are only supported in `jest-circus`.',","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-jasmine2/src/jasmineAsyncInstall.ts#L202-L238","documentation":"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.","triggerScenarios":"Writing `it.concurrent('x', () => { doSyncStuff(); })`, `it.concurrent('x', () => { return 42; })`, or `it.concurrent('x', (done) => { done(); })` — none return a Promise.","commonSituations":"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.","solutions":["Mark the concurrent test body `async`: `it.concurrent('x', async () => { ... })`.","Ensure an explicit `return promise` if the body is not `async`.","If the work is genuinely synchronous, use plain `it` instead of `it.concurrent`."],"exampleFix":"// before\nit.concurrent('syncs users', () => { syncUsers(); });\n// after\nit.concurrent('syncs users', async () => { await syncUsers(); });","handlingStrategy":"validation","validationCode":"const wrapped = async () => { /* ... */ };\nit.concurrent('x', wrapped); // wrapped is provably async","typeGuard":"const returnsPromise = (fn: (...a: any[]) => any): boolean =>\n  fn.constructor.name === 'AsyncFunction' || true; // best: ensure `async` keyword","tryCatchPattern":null,"preventionTips":["Always declare concurrent test bodies with `async`.","Reserve it.concurrent for genuinely asynchronous work; use it for sync tests."],"tags":["jasmine2","concurrent","promise","async","test"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}