vitest-dev/vitest · error · Error
Hook ${name}() can only be called inside a test
Error message
Hook ${name}() can only be called inside a test What it means
`onTestFailed` and `onTestFinished` are test-scoped hooks created via `createTestHook` (hooks.ts:444). They require an active test (`getCurrentTest()` must be truthy) at call time. If called outside any test body — at the top level, inside `describe`, inside `beforeAll`/`beforeEach`, or after the test has finished — there is no current test to attach the hook to, so the error is thrown with the hook name.
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 d568f8ce37)
Solutions
- Move the `onTestFailed`/`onTestFinished` call inside a `test(...)` body.
- For suite-level setup/teardown, use `beforeAll`/`afterAll` or `beforeEach`/`afterEach` instead.
- Ensure the hook is registered synchronously while the test is the current task.
Example fix
// before
describe('suite', () => {
onTestFailed(() => { /* wrong place */ })
test('x', () => {})
})
// after
describe('suite', () => {
test('x', () => {
onTestFailed(() => { /* correct */ })
})
}) Defensive patterns
Strategy: validation
Validate before calling
// Structural check: ensure onTestFailed/onTestFinished calls are lexically inside a test. // In practice, rely on the runtime check; statically, forbid these calls in hooks via lint: // 'no-restricted-syntax' banning onTestFailed/onTestFinished inside beforeEach/afterEach/beforeAll/afterAll blocks.
Prevention
- Always place onTestFailed/onTestFinished directly inside a test() body.
- Use afterEach/afterAll for cleanup that must run regardless.
- Avoid sharing helpers that register test-scoped hooks.
When it happens
Trigger: Calling `onTestFailed(fn)` at module top level; calling it inside a `describe` factory body directly (not inside a test); calling `onTestFinished` inside `beforeEach`/`beforeAll` suite hooks; calling after the current test already completed.
Common situations: Placing cleanup handlers at the wrong nesting level; copy-pasting a hook out of a test; refactoring that moves a hook call into a suite-level setup.
Related errors
- Cannot call "onTestFailed" inside a test hook.
- Cannot call "onTestFinished" inside a test hook.
- Cannot take a screenshot outside of a test.
- 'toMatchScreenshot' cannot be used without test context
- Cannot annotate tests outside of the test run. The test "${t
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/2deacf699ecb7128.json.
Report an issue: GitHub.