{"id":"60caa7fcd816f695","repo":"jestjs/jest","slug":"a-describe-callback-must-not-return-a-value","errorCode":null,"errorMessage":"A \"describe\" callback must not return a value.","messagePattern":"A \"describe\" callback must not return a value\\.","errorType":"exception","errorClass":"ErrorWithStack","httpStatus":null,"severity":"error","filePath":"packages/jest-circus/src/index.ts","lineNumber":84,"sourceCode":"    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,\n) => {\n  const asyncError = new ErrorWithStack(undefined, hookFn);\n\n  if (typeof fn !== 'function') {\n    asyncError.message =","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-circus/src/index.ts#L66-L102","documentation":"After the Promise check, jest-circus also rejects any non-undefined return value from a describe callback (packages/jest-circus/src/index.ts:83). describe must only register tests/hooks via side effects; returning a value is treated as a mistake because that value is silently discarded by the runner and usually indicates an unintended arrow-function return.","triggerScenarios":"`describe('x', () => configure())` where configure() returns a non-Promise value; `describe('x', () => { return config; })`; an arrow callback whose last expression evaluates to an object/array/number.","commonSituations":"Refactoring a function into a describe body and forgetting to convert an expression-bodied arrow to a statement block. Returning a helper's result that the author assumed would be used.","solutions":["Convert the describe callback to a block body that does not return: `describe('x', () => { configure(); })`.","If the value is meant to be shared across tests, assign it to a variable declared in the describe scope or move the computation into beforeAll.","Add an eslint rule or code review check that flags returned values inside describe."],"exampleFix":"// before\ndescribe('config', () => loadConfig());\n\n// after\ndescribe('config', () => {\n  loadConfig();\n});","handlingStrategy":"validation","validationCode":"// Ensure the describe factory returns nothing.\nfunction syncDescribe(name: string, fn: () => void): void {\n  const result = fn();\n  if (result !== undefined) throw new Error('describe callback returned a value');\n}","typeGuard":"type DescribeFn = () => void; // enforce void return via TS\nconst isVoidReturning = (fn: () => unknown): fn is () => void => true;","tryCatchPattern":null,"preventionTips":["Type describe callbacks as `() => void` so TS flags returned values.","Avoid expression-bodied arrows inside describe.","Code-review for accidental returns after refactors."],"tags":["jest-circus","describe","test-definition"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}