vitest-dev/vitest · error · AroundHookSetupError

The `${callbackName}` callback was not called in the `${hook

Error message

The `${callbackName}` callback was not called in the `${hookName}` hook. Make sure to call `${callbackName}` to run the ${hookName === 'aroundEach' ? 'test' : 'suite'}.

What it means

If an `aroundEach`/`aroundAll` hook function returns/resolves without ever calling the provided `runTest`/`runSuite` callback, `callAroundHooks` detects that `useCalled` is still false after the hook completes and throws an `AroundHookSetupError` (run.ts:385-390). The hook must invoke the callback so the inner tests/suite actually run.

Source

Thrown at packages/vitest/src/runtime/runner/run.ts:386

      // Start teardown timer after inner hooks complete - only times this hook's teardown code
      teardownTimeout = createTimeoutPromise(timeout, 'teardown', stackTraceError)

      // Signal that use() is returning (teardown phase starting)
      resolveUseReturned()
    }

    setupLimitConcurrencyRelease = await limitMaxConcurrency.acquire()

    // Start setup timeout
    setupTimeout = createTimeoutPromise(timeout, 'setup', stackTraceError)

    // Run the hook in the background
    ;(async () => {
      try {
        await invokeHook(hook, use)
        if (!useCalled) {
          throw new AroundHookSetupError(
            `The \`${callbackName}\` callback was not called in the \`${hookName}\` hook. `
            + `Make sure to call \`${callbackName}\` to run the ${hookName === 'aroundEach' ? 'test' : 'suite'}.`,
          )
        }
        resolveHookComplete()
      }
      catch (error) {
        rejectHookComplete(error as Error)
      }
      finally {
        setupLimitConcurrencyRelease?.()
        teardownLimitConcurrencyRelease?.()
      }
    })()

    // Wait for either: use() to be called OR hook to complete (error) OR setup timeout
    try {
      await Promise.race([

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Ensure every code path in the around hook calls `runTest`/`runSuite` exactly once.
  2. Place the callback call on the unconditional main path, before teardown.
  3. If the hook should skip the test/suite, use skip mechanisms instead of omitting the call.

Example fix

// before
aroundEach(async (runTest) => {
  await setup()
  // forgot to call runTest()
})
// after
aroundEach(async (runTest) => {
  await setup()
  await runTest()
  await teardown()
})
Defensive patterns

Strategy: validation

Validate before calling

// Static reminder: every aroundEach/aroundAll must contain a runTest()/runSuite() call.
// Use a lint rule requiring the callback name to appear at least once in the hook body.

Prevention

When it happens

Trigger: An `aroundEach` hook that forgets to call `runTest()`; an `aroundAll` hook that returns early before `runSuite()`; an awaited condition that throws/swallows before reaching the callback call.

Common situations: Forgetting the callback after refactoring; conditional logic that skips the call on some path; early return/throw that bypasses runTest.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/637c23b25bb37162.json. Report an issue: GitHub.