vitest-dev/vitest · error · TypeError

${matcherHint('.toBeFasterThan')} expects the actual value t

Error message

${matcherHint('.toBeFasterThan')} expects the actual value to be a benchmark result.

What it means

Thrown by the toBeFasterThan benchmark matcher in packages/vitest/src/integrations/chai/bench.ts when the actual value (the receiver of expect()) is not a BenchResult — i.e. an object with a numeric latency.mean produced by vitest's bench() API. The matcher compares benchmark statistics, so passing a plain number or non-bench object makes the comparison meaningless; Vitest throws a TypeError rather than silently degrading.

Source

Thrown at packages/vitest/src/integrations/chai/bench.ts:23

  return (
    typeof value === 'object'
    && value !== null
    && 'latency' in value
    && typeof (value as any).latency?.mean === 'number'
  )
}

function formatOps(ops: number): string {
  return ops.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}

export const benchMatchers: MatchersObject = {
  toBeFasterThan(actual: unknown, expected: unknown, options?: { delta?: number }) {
    const { matcherHint, RECEIVED_COLOR, EXPECTED_COLOR } = this.utils
    const delta = options?.delta ?? 0

    if (!isBenchResult(actual)) {
      throw new TypeError(
        `${matcherHint('.toBeFasterThan')} expects the actual value to be a benchmark result.`,
      )
    }
    if (!isBenchResult(expected)) {
      throw new TypeError(
        `${matcherHint('.toBeFasterThan')} expects the expected value to be a benchmark result.`,
      )
    }

    const threshold = expected.latency.mean * (1 - delta)
    const pass = actual.latency.mean < threshold

    return {
      pass,
      message: () => {
        const relation = ((actual.latency.mean - expected.latency.mean) / expected.latency.mean * 100).toFixed(2)
        return pass
          ? `${matcherHint('.not.toBeFasterThan')}\n\nExpected to not be faster, but was ${Math.abs(Number(relation))}% faster.\n\n`

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Use toBeFasterThan only inside a bench() task, passing the benchmark result object that vitest provides.
  2. For plain numeric comparisons use toBeLessThan, not toBeFasterThan.
  3. Capture the BenchResult from bench() and pass it to expect(): const result = await bench(...); expect(result).toBeFasterThan(baseline).
  4. Confirm you imported the bench matchers (they ship with vitest) and are inside a benchmark run.

Example fix

// before
expect(50).toBeFasterThan(baseline)

// after
import { bench, expect } from 'vitest'
bench('op', () => { /* ... */ })
// inside a benchmark task, expect() receives the BenchResult
expect(actualBenchResult).toBeFasterThan(baselineBenchResult)
Defensive patterns

Strategy: type-guard

Validate before calling

function isBenchResult(value: unknown): value is { latency: { mean: number }; throughput: { mean: number } } {
  return typeof value === 'object' && value !== null
    && 'latency' in value && typeof (value as any).latency?.mean === 'number'
}

Type guard

function isBenchResult(value: unknown): value is { latency: { mean: number }; throughput: { mean: number } } {
  return typeof value === 'object' && value !== null
    && 'latency' in value && typeof (value as any).latency?.mean === 'number'
}

Prevention

When it happens

Trigger: expect(myNumber).toBeFasterThan(other); using toBeFasterThan outside of a bench() task where expect() receives the result of a normal assertion; passing a raw timing value instead of the BenchResult returned by bench.

Common situations: Confusing benchmark matchers with regular numeric matchers; refactoring a bench task so expect() no longer receives the BenchResult; calling toBeFasterThan inside an it() instead of a bench() block.

Related errors


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