{"id":"250a7657136d639c","repo":"vitest-dev/vitest","slug":"bench-compare-expects-every-argument-to-be-the","errorCode":null,"errorMessage":"`bench.compare()` expects every argument to be the return value of `bench` or `bench.from`.","messagePattern":"`bench\\.compare\\(\\)` expects every argument to be the return value of `bench` or `bench\\.from`\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/benchmark.ts","lineNumber":479,"sourceCode":"    const isOptions = lastArg != null && typeof lastArg === 'object' && !(kRegistration in lastArg)\n    const benchOptions = isOptions ? args.pop() as BenchRunOptions : undefined\n    const registrations = args as BenchRegistration<any>[]\n\n    // Mark every passed-in registration as consumed before validation so a\n    // throwing `bench.compare()` (wrong arity, wrong shape) doesn't also\n    // trigger the unrun-bench warning — the user's intent was to consume them.\n    for (const reg of registrations) {\n      if (reg != null && typeof reg === 'object' && kRegistration in reg) {\n        pending.delete(reg)\n      }\n    }\n\n    if (registrations.length < 2) {\n      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`)\n    }\n    for (const reg of registrations) {\n      if (reg == null || typeof reg !== 'object' || !(kRegistration in reg)) {\n        throw new SyntaxError('`bench.compare()` expects every argument to be the return value of `bench` or `bench.from`.')\n      }\n    }\n\n    const runnable: RunnableRegistration<any>[] = []\n    const fromEntries: FromRegistration<any>[] = []\n    for (const reg of registrations) {\n      if (isFromRegistration(reg)) {\n        fromEntries.push(reg)\n      }\n      else {\n        runnable.push(reg as RunnableRegistration<any>)\n      }\n    }\n\n    const taskMeta = new Map<string, TaskMeta>()\n    for (const reg of runnable) {\n      if (reg[kPerProject]) {\n        taskMeta.set(reg.name, { perProject: true })","sourceCodeStart":461,"sourceCodeEnd":497,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/runtime/benchmark.ts#L461-L497","documentation":"Every positional argument to `bench.compare()` must be a `BenchRegistration` returned by `bench()` or `bench.from()` (detected via the internal `kRegistration` symbol). This `SyntaxError` (see `benchmark.ts:479`) fires when any argument is `null`, not an object, or lacks the symbol — e.g. passing a raw function, a string name, a `BenchResult`, or the result of `.run()`.","triggerScenarios":"Passing `bench('a', fn).run()` (which is a `Promise<BenchResult>`) instead of the registration; passing a string name; passing `undefined`; passing a plain function.","commonSituations":"Accidentally awaiting/calling `.run()` before `compare`; destructuring the wrong variable; mixing up the registration object with its result.","solutions":["Pass the raw registration objects, not their results: `const a = bench('a', fn); await bench.compare(a, b)`.","Ensure no `.run()` is called on registrations you intend to compare — `compare` runs them itself.","Filter out nullish entries before spreading: `bench.compare(...regs.filter(Boolean))`."],"exampleFix":"// before\nawait bench.compare(\n  bench('a', fnA).run(),\n  bench.from('b', path)\n)\n\n// after\nconst a = bench('a', fnA)\nconst b = bench.from('b', path)\nawait bench.compare(a, b)","handlingStrategy":"validation","validationCode":"// Ensure every arg is a non-null object produced by bench()/bench.from().\n// The internal kRegistration symbol isn't user-accessible, so infer by shape:\nfunction looksLikeRegistration(v: unknown): v is { run: Function; name: string } {\n  return v != null && typeof v === 'object'\n    && typeof (v as any).run === 'function'\n    && typeof (v as any).name === 'string'\n}\nconst clean = args.filter(looksLikeRegistration)\nif (clean.length !== args.length) {\n  throw new Error('One or more bench.compare args are not registrations')\n}\nawait bench.compare(...clean)","typeGuard":"function isBenchRegistrationLike(v: unknown): v is { name: string; run: (o?: any) => Promise<any> } {\n  return v != null && typeof v === 'object'\n    && typeof (v as any).name === 'string'\n    && typeof (v as any).run === 'function'\n}","tryCatchPattern":"try {\n  await bench.compare(...regs)\n} catch (e) {\n  if (e instanceof SyntaxError && /expects every argument/.test(e.message)) {\n    // remove any non-registration entries and retry\n  } else throw e\n}","preventionTips":["Pass the raw registration objects — never their .run() results.","Avoid spreading arrays that might contain null/undefined; filter first.","Keep a single source of truth for registrations rather than recomputing them inline."],"tags":["benchmark","bench-compare","api-misuse","validation","syntaxerror"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}