vitest-dev/vitest · error · Error

Hook () can only be called inside a test

Error message

Hook ${name}() can only be called inside a test

What it means

Thrown by createTestHook, the factory behind onTestFailed and onTestFinished. These hooks bind to the currently executing test, so they require a live test context (getCurrentTest() must return a test). Calling them at module top-level, inside describe/setup hooks, or inside beforeAll/afterAll yields no current test and triggers this error.

Solutions

  1. Move the onTestFailed/onTestFinished call inside the test() callback body.
  2. For shared logic, accept the context as a parameter and call `context.onTestFinished` from within the test.
  3. Use beforeEach/afterEach for setup/teardown that applies to every test rather than onTestFinished.

Example fix

// before
beforeEach(() => {
  onTestFailed(() => cleanup()) // throws: not in a test
})

// after
test('x', () => {
  onTestFailed(() => cleanup())
})
Defensive patterns

Strategy: validation

Validate before calling

import { getCurrentTest } from 'vitest'
function registerAfterTest(fn: () => void) {
  if (!getCurrentTest()) throw new Error('onTestFinished must be called inside a test')
  onTestFinished(fn)
}

Type guard

const inTest = () => !!getCurrentTest()

Prevention

When it happens

Trigger: Calling `onTestFailed(fn)` or `onTestFinished(fn)` at the top level of a test file; inside a beforeAll/afterAll/beforeEach/afterEach hook body (those run outside the test execution frame); inside describe factory body before any test runs.

Common situations: Factoring shared cleanup into a helper that calls onTestFinished unconditionally; pasting test-body code into a hook during refactor; calling onTestFailed from a setup utility module.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/2deacf699ecb7128. Report an issue: GitHub.

Appendix: source

Thrown at packages/vitest/src/runtime/runner/hooks.ts:454

}

export function getAroundHookStackTrace(hook: Function): Error | undefined {
  return AROUND_STACK_TRACE_KEY in hook && hook[AROUND_STACK_TRACE_KEY] instanceof Error
    ? hook[AROUND_STACK_TRACE_KEY]
    : undefined
}

function createTestHook<T>(
  name: string,
  handler: (test: TaskPopulated, handler: T, timeout?: number) => void,
): TaskHook<T> {
  return (fn: T, timeout?: number) => {
    assertTypes(fn, `"${name}" callback`, ['function'])

    const current = getCurrentTest()

    if (!current) {
      throw new Error(`Hook ${name}() can only be called inside a test`)
    }

    return handler(current, fn, timeout)
  }
}

View on GitHub (pinned to 1fa9837ec2)