vitest-dev/vitest · error · Error
Cannot call "onTestFailed" inside a test hook.
Error message
Cannot call "onTestFailed" inside a test hook.
What it means
While `beforeEach`/`afterEach` (and onFinished/onFailed) hooks execute, Vitest temporarily replaces `context.onTestFailed` with a function that throws this error (run.ts:138-140). This prevents registering a failure handler for an already-finishing test from within a hook, where the registration semantics are ambiguous.
Source
Thrown at packages/vitest/src/runtime/runner/run.ts:139
runner: VitestRunner,
test: Test,
hooks: ((context: TestContext) => Awaitable<void>)[],
sequence: SequenceHooks,
) {
if (sequence === 'stack') {
hooks = hooks.slice().reverse()
}
if (!hooks.length) {
return
}
const context = test.context as WriteableTestContext
const onTestFailed = test.context.onTestFailed
const onTestFinished = test.context.onTestFinished
context.onTestFailed = () => {
throw new Error(`Cannot call "onTestFailed" inside a test hook.`)
}
context.onTestFinished = () => {
throw new Error(`Cannot call "onTestFinished" inside a test hook.`)
}
if (sequence === 'parallel') {
try {
await Promise.all(hooks.map(fn => limitMaxConcurrency(() => fn(test.context))))
}
catch (e) {
failTask(test.result!, e, runner.config._diffOptions)
}
}
else {
for (const fn of hooks) {
try {
await limitMaxConcurrency(() => fn(test.context))
}View on GitHub (pinned to d568f8ce37)
Solutions
- Register `onTestFailed` inside the test body itself, not inside hooks.
- If you need conditional failure handling per test, pass a flag and register the handler in each test.
- Use `afterEach` for cleanup that must run regardless, instead of onTestFailed.
Example fix
// before
beforeEach(({ onTestFailed }) => {
onTestFailed(() => cleanup()) // throws
})
// after
afterEach(() => {
cleanup()
}) Defensive patterns
Strategy: validation
Validate before calling
// Cannot call onTestFailed from a hook by design; the guard is structural. // Ensure no beforeEach/afterEach body references onTestFailed. // Grep your suite: rg 'onTestFailed' inside hook definitions.
Prevention
- Never reference onTestFailed inside beforeEach/afterEach.
- Use afterEach for cleanup that previously lived in onTestFailed.
- Register failure handlers inside the test body.
When it happens
Trigger: Calling `context.onTestFailed(fn)` (or `onTestFailed(fn)` where globals resolve to the context's method) from inside a `beforeEach` or `afterEach` hook body.
Common situations: Sharing setup logic that registers failure handlers; refactoring test helpers into hooks without realizing they call onTestFailed.
Related errors
- Hook ${name}() can only be called inside a test
- 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/1e7573a3db72fcca.json.
Report an issue: GitHub.