{"record":{"id":"a23593129b58c08e","repo":"jestjs/jest","slug":"returning-a-promise-from-describe-is-not-support","errorCode":null,"errorMessage":"Returning a Promise from \"describe\" is not supported. Tests must be defined synchronously.","messagePattern":"Returning a Promise from \"describe\" is not supported\\. Tests must be defined synchronously\\.","errorType":"exception","errorClass":"ErrorWithStack","httpStatus":null,"severity":"error","filePath":"packages/jest-circus/src/index.ts","lineNumber":79,"sourceCode":"    throw asyncError;\n  }\n  try {\n    blockName = convertDescriptorToString(blockName);\n  } catch (error) {\n    asyncError.message = (error as Error).message;\n    throw asyncError;\n  }\n\n  dispatchSync({\n    asyncError,\n    blockName,\n    mode,\n    name: 'start_describe_definition',\n  });\n  const describeReturn = blockFn();\n\n  if (isPromise(describeReturn)) {\n    throw new ErrorWithStack(\n      'Returning a Promise from \"describe\" is not supported. Tests must be defined synchronously.',\n      describeFn,\n    );\n  } else if (describeReturn !== undefined) {\n    throw new ErrorWithStack(\n      'A \"describe\" callback must not return a value.',\n      describeFn,\n    );\n  }\n\n  dispatchSync({blockName, mode, name: 'finish_describe_definition'});\n};\n\nconst _addHook = (\n  fn: Circus.HookFn,\n  hookType: Circus.HookType,\n  hookFn: THook,\n  timeout?: number,","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/jest-circus/src/index.ts#L61-L97","documentation":"Jest's test registry is built synchronously: when you call describe(), jest-circus immediately executes your callback (index.ts:76) to collect child test/hook registrations into its event tree. If that callback returns a Promise, the registry would be incomplete at dispatch time, so _dispatchDescribe rejects it outright (index.ts:78-82). Async setup work belongs in beforeAll/beforeEach, which DO run asynchronously during the later run() phase.","triggerScenarios":"Calling describe('suite', async () => {...}), or returning any thenable from the describe callback (e.g. describe('x', () => someAsyncFn())), or wrapping the body in an async IIFE. The check uses isPromise() on the return value of blockFn() at index.ts:76-78.","commonSituations":"Migrating from Mocha where describe callbacks could be async; refactoring setup code and accidentally marking the describe arrow function async; calling an async helper at the top level of describe instead of inside beforeAll.","solutions":["Move the async logic into a beforeAll hook inside the describe (beforeAll(async () => { await ... })).","If the async work produces values needed by tests, assign them in beforeAll to variables declared in the describe scope.","Keep the describe callback purely synchronous: it should only register tests and hooks, never perform setup.","For data-driven async setup, use beforeAll with jest.each or compute the data synchronously."],"exampleFix":"// before\ndescribe('users', async () => {\n  const user = await createUser();\n  test('has name', () => expect(user.name).toBe('a'));\n});\n// after\ndescribe('users', () => {\n  let user: User;\n  beforeAll(async () => {\n    user = await createUser();\n  });\n  test('has name', () => expect(user.name).toBe('a'));\n});","handlingStrategy":"validation","validationCode":"// Before writing a describe, enforce that its callback is not async.\nfunction assertSyncDescribe(fn: (...args: any[]) => any): void {\n  if (fn.constructor.name === 'AsyncFunction') {\n    throw new Error('describe callback must not be async; use beforeAll for async setup');\n  }\n}\n// usage:\nconst cb = () => { test('x', () => {}); };\nassertSyncDescribe(cb);\ndescribe('suite', cb);","typeGuard":"function isSyncDescribeFn(fn: unknown): fn is () => void {\n  return typeof fn === 'function' && fn.constructor.name !== 'AsyncFunction';\n}","tryCatchPattern":null,"preventionTips":["Enable an eslint rule (e.g. jest/no-async-describe community rule) to reject async describe callbacks at lint time.","Keep describe bodies to registration only; do all async work in beforeAll/beforeEach.","In code review, flag any 'async' keyword on a describe callback."],"tags":["jest-circus","describe","async","synchronous","test-registration"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}