vitest-dev/vitest · error · Error

Cannot call "onTestFinished" inside a test hook.

Error message

Cannot call "onTestFinished" inside a test hook.

What it means

Symmetric to error 347, during hook execution Vitest replaces `context.onTestFinished` with a throwing stub (run.ts:141-143). Registering an onTestFinished handler from within `beforeEach`/`afterEach` is disallowed because the registration window for that test has effectively closed.

Source

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

  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))
      }
      catch (e) {
        failTask(test.result!, e, runner.config._diffOptions)
      }

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Register `onTestFinished` inside the test body, not in hooks.
  2. Use `afterEach` for guaranteed post-test cleanup instead of onTestFinished.
  3. Restructure shared setup helpers to return cleanup callbacks the caller invokes.

Example fix

// before
beforeEach(({ onTestFinished }) => {
  const db = connect()
  onTestFinished(() => db.close()) // throws
})
// after
afterEach(() => {
  closeDbIfOpen()
})
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no beforeEach/afterEach body references onTestFinished.
// Grep: rg 'onTestFinished' within hook callbacks; move logic to afterEach.

Prevention

When it happens

Trigger: Calling `context.onTestFinished(fn)` or the global `onTestFinished(fn)` from inside a `beforeEach`/`afterEach` hook.

Common situations: Porting onTestFinished-based cleanup into a shared hook; helpers that wrap both setup and teardown registration.

Related errors


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