vitest-dev/vitest · error · Error

snapshot function didn't throw

Error message

snapshot function didn't throw

What it means

After confirming the subject is a function, `getError` invokes it expecting it to throw so the thrown value can be snapshotted. If the function returns normally without throwing, there is no error to snapshot, so Vitest throws `snapshot function didn't throw`. This is the synchronous counterpart of `getError`; in a promise context the error is received directly instead.

Source

Thrown at packages/vitest/src/integrations/snapshot/chai.ts:46

  if (typeof expected !== 'function') {
    if (!promise) {
      throw new Error(
        `expected must be a function, received ${typeof expected}`,
      )
    }

    // when "promised", it receives thrown error
    return expected
  }

  try {
    expected()
  }
  catch (e) {
    return e
  }

  throw new Error('snapshot function didn\'t throw')
}

function getTestNames(test: Test) {
  return {
    filepath: test.file.filepath,
    name: getNames(test).slice(1).join(' > '),
    testId: test.id,
  }
}

function getAssertionName(assertion: Chai.Assertion): string {
  const name = chai.util.flag(assertion, '_name') as string | undefined
  if (!name) {
    throw new Error('Assertion name is not set. This is a bug in Vitest. Please, open a new issue with reproduction.')
  }
  return name
}

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Confirm the function still throws for the given input by running it directly first.
  2. Update the test to use input that does throw, or switch to a non-throw snapshot matcher if the behavior changed.
  3. Remove any internal `try/catch` that swallows the error inside the wrapped function.

Example fix

// before
expect(() => validate('ok')).toThrowErrorMatchingSnapshot() // validate no longer throws on 'ok'
// after
expect(() => validate('')).toThrowErrorMatchingSnapshot() // input that actually throws
Defensive patterns

Strategy: try-catch

Validate before calling

function capturesError(fn: () => unknown): boolean {
  try { fn(); return false } catch { return true }
}
if (!capturesError(() => risky())) throw new Error('function does not throw; nothing to snapshot')

Try / catch

try {
  risky()
  throw new Error('expected risky() to throw before snapshotting')
} catch (e) {
  expect(() => { throw e }).toThrowErrorMatchingSnapshot()
}

Prevention

When it happens

Trigger: `expect(() => { /* returns normally */ }).toThrowErrorMatchingSnapshot()` / `...InlineSnapshot()` where the wrapped function does not actually throw.

Common situations: The function was refactored to no longer throw, the triggering input changed, or an earlier `try/catch` swallowed the error before it could propagate out of the wrapped function.

Related errors


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