vitest-dev/vitest · error · SyntaxError
`bench.compare()` requires at least 2 benchmarks, received
Error message
`bench.compare()` requires at least 2 benchmarks, received ${registrations.length} instead. ${registrations.length === 1 ? 'Consider calling `bench().run()`. ' : 'Define benchmarks by calling `bench()`. '}See https://vitest.dev/guide/benchmarking#comparing-benchmarks What it means
`bench.compare(...)` requires at least two benchmark registrations — comparison is meaningless with fewer. This `SyntaxError` fires when zero or one registrations are passed (after stripping a trailing options object). The error message dynamically hints: with 1 registration it suggests `bench().run()`; with 0 it suggests defining benchmarks via `bench()`.
Solutions
- Pass at least two registrations: `await bench.compare(regA, regB)`.
- If you have a single benchmark, call `await reg.run()` or `await bench('name', fn).run()` instead of `bench.compare`.
- If passing run options, ensure they are the LAST argument and at least two registrations precede them: `bench.compare(regA, regB, { iterations: 100 })`.
Example fix
// before
const a = bench('sort', sortFn)
await bench.compare(a) // only one
// after
await a.run() // single benchmark
// or
const b = bench('sort2', sort2Fn)
await bench.compare(a, b) Defensive patterns
Strategy: validation
Validate before calling
if (registrations.length < 2) throw new Error(`need >=2 registrations, got ${registrations.length}`) Type guard
function hasMinTwo<T>(arr: T[]): arr is [T, T, ...T[]] { return arr.length >= 2 } Try / catch
null
Prevention
- Use `bench().run()` for single benchmarks instead of `bench.compare`.
- When building args dynamically, assert `regs.length >= 2` before calling.
- Place trailing run options only after at least two registrations.
When it happens
Trigger: Calling `bench.compare(singleReg)` (1 arg), `bench.compare()` (0 args), or `bench.compare(singleReg, optionsObj)` where the trailing object is detected as `BenchRunOptions` and stripped, leaving one registration. Detection at benchmark.ts:460-462 pops the last arg when it is an object without the `kRegistration` symbol.
Common situations: Forgetting to register a second baseline; passing the options object as the only non-registration argument; conditionally building the args array and ending with one element; refactoring `bench().run()` into `bench.compare()` without adding a second benchmark.
Related errors
- `bench.compare()` expects every argument to be the return…
- task " " was not defined
- `bench()` expects a benchmark function. Call `bench(name…
- `bench.from()` expects a string path or a function…
- `bench.from()` requires a name (string or named function)…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/2bb8a6f3802fb704.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/runtime/benchmark.ts:475
validateBenchmarkProject(config)
// extract optional trailing BenchRunOptions argument
const lastArg = args.at(-1)
const isOptions = lastArg != null && typeof lastArg === 'object' && !(kRegistration in lastArg)
const benchOptions = isOptions ? args.pop() as BenchRunOptions : undefined
const registrations = args as BenchRegistration<any>[]
// Mark every passed-in registration as consumed before validation so a
// throwing `bench.compare()` (wrong arity, wrong shape) doesn't also
// trigger the unrun-bench warning — the user's intent was to consume them.
for (const reg of registrations) {
if (reg != null && typeof reg === 'object' && kRegistration in reg) {
pending.delete(reg)
}
}
if (registrations.length < 2) {
throw new SyntaxError(`\`bench.compare()\` requires at least 2 benchmarks, received ${registrations.length} instead. ${registrations.length === 1 ? 'Consider calling `bench().run()`. ' : 'Define benchmarks by calling `bench()`. '}See https://vitest.dev/guide/benchmarking#comparing-benchmarks`)
}
for (const reg of registrations) {
if (reg == null || typeof reg !== 'object' || !(kRegistration in reg)) {
throw new SyntaxError('`bench.compare()` expects every argument to be the return value of `bench` or `bench.from`.')
}
}
const runnable: RunnableRegistration<any>[] = []
const fromEntries: FromRegistration<any>[] = []
for (const reg of registrations) {
if (isFromRegistration(reg)) {
fromEntries.push(reg)
}
else {
runnable.push(reg as RunnableRegistration<any>)
}
}
View on GitHub (pinned to 1fa9837ec2)