jestjs/jest · error · ErrorWithStack

A "describe" callback must not return a value.

Error message

A "describe" callback must not return a value.

What it means

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.

Source

Thrown at packages/jest-circus/src/index.ts:84

    asyncError.message = (error as Error).message;
    throw asyncError;
  }

  dispatchSync({
    asyncError,
    blockName,
    mode,
    name: 'start_describe_definition',
  });
  const describeReturn = blockFn();

  if (isPromise(describeReturn)) {
    throw new ErrorWithStack(
      'Returning a Promise from "describe" is not supported. Tests must be defined synchronously.',
      describeFn,
    );
  } else if (describeReturn !== undefined) {
    throw new ErrorWithStack(
      'A "describe" callback must not return a value.',
      describeFn,
    );
  }

  dispatchSync({blockName, mode, name: 'finish_describe_definition'});
};

const _addHook = (
  fn: Circus.HookFn,
  hookType: Circus.HookType,
  hookFn: THook,
  timeout?: number,
) => {
  const asyncError = new ErrorWithStack(undefined, hookFn);

  if (typeof fn !== 'function') {
    asyncError.message =

View on GitHub (pinned to f49721c78e)

Solutions

  1. Convert the describe callback to a block body that does not return: `describe('x', () => { configure(); })`.
  2. 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.
  3. Add an eslint rule or code review check that flags returned values inside describe.

Example fix

// before
describe('config', () => loadConfig());

// after
describe('config', () => {
  loadConfig();
});
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the describe factory returns nothing.
function syncDescribe(name: string, fn: () => void): void {
  const result = fn();
  if (result !== undefined) throw new Error('describe callback returned a value');
}

Type guard

type DescribeFn = () => void; // enforce void return via TS
const isVoidReturning = (fn: () => unknown): fn is () => void => true;

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


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