vitest-dev/vitest · error · AssertionError

expected function to throw an error, but it didn't

Error message

expected function to throw an error, but it didn't

What it means

Thrown by `toThrow`/`toThrowError` when the subject function ran to completion without raising. The matcher invokes the function, and if `isThrow` stays false (and `.not` is not set), it raises `AssertionError`. This is the core failure path for a negative `toThrow`.

Solutions

  1. Make the test inputs force the error branch (pass invalid arguments, set failing state).
  2. If the function legitimately should not throw, remove the `toThrow` assertion or invert with `.not.toThrow()`.
  3. Ensure internal try/catch does not swallow the error before it propagates.

Example fix

// before
expect(() => validate('')).toThrow()
// validate returns silently

// after
expect(() => validate('')).toThrow('required')
// after fixing validate to throw on empty input
Defensive patterns

Strategy: validation

Validate before calling

let threw = false
try { fn() } catch { threw = true }
if (!threw) { throw new Error('setup did not produce a throw') }

Prevention

When it happens

Trigger: Calling `expect(fn).toThrow()` on a function that does not throw; expecting a specific error but the code path skipped the throw branch (e.g. guarded by a condition that was false).

Common situations: Writing the test before the error path exists; condition guarding the throw was satisfied so the branch was skipped; the function swallowed errors internally with try/catch.

Related errors


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

Appendix: source

Thrown at packages/expect/src/jest-expect.ts:802

      }
      else {
        let isThrow = false
        try {
          obj()
        }
        catch (err) {
          isThrow = true
          thrown = err
        }

        if (!isThrow && !isNot) {
          const message
            = utils.flag(this, 'message')
              || 'expected function to throw an error, but it didn\'t'
          const error = {
            showDiff: false,
          }
          throw new AssertionError(message, error, utils.flag(this, 'ssfi'))
        }
      }

      if (typeof expected === 'function') {
        const name = expected.name || expected.prototype.constructor.name
        return this.assert(
          thrown && thrown instanceof expected,
          `expected error to be instance of ${name}`,
          `expected error not to be instance of ${name}`,
          expected,
          thrown,
        )
      }

      if (isError(expected)) {
        const equal = jestEquals(thrown, expected, [
          ...customTesters,
          iterableEquality,

View on GitHub (pinned to 1fa9837ec2)