vitest-dev/vitest · error · Error

Expected a single value for option

Error message

Expected a single value for option "${command}", received [${received}]

What it means

Thrown by the CLI option `transform` when an option declared as a single value (no `array: true`) receives more than one value across the command line. Vitest wraps `cac` and rejects multi-value input for scalar options so that ambiguous invocations fail loudly instead of silently keeping only the last value.

Solutions

  1. Pass the option exactly once: `--name value` instead of `--name a --name b`.
  2. If you genuinely need multiple values, switch to the array form of the option (e.g. `--reporters dot --reporters json`) if one exists.
  3. Inspect the option definition in `cli-config.ts` to confirm whether `array: true` is set; if not, it is scalar by design.
  4. Quote the value if a shell is splitting it: `--filter "a b"`.

Example fix

// before
vitest run --reporter=dot --reporter=json

// after (reporters is the array option)
vitest run --reporters=dot --reporters=json
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking parseCLI / cac, dedupe scalar flags.
function dedupeScalarFlags(argv: string[]): string[] {
  const seen = new Set<string>()
  const out: string[] = []
  for (let i = 0; i < argv.length; i++) {
    const a = argv[i]
    const m = a.match(/^--([\w-]+)(?:=(.*))?$/)
    if (m) {
      if (seen.has(m[1])) continue // keep first occurrence only
      seen.add(m[1])
    }
    out.push(a)
  }
  return out
}

Prevention

When it happens

Trigger: Passing the same scalar flag twice (e.g. `--reporter=dot --reporter=json` when `reporter` is not an array option), or an option that expects one argument receiving a comma/space-separated list that `cac` splits into an array. The check is `!option.array && Array.isArray(value)`.

Common situations: Copy-pasting CLI flags from a script that already set the option; assuming an option accepts repeats because a sibling option does (`reporters` is `array: true` while `reporter` historically was not); shell expansion turning a glob into multiple args for a scalar flag.

Related errors


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

Appendix: source

Thrown at packages/vitest/src/node/cli/cac.ts:23

import cac from 'cac'
import { normalize } from 'pathe'
import { disableDefaultColors } from 'tinyrainbow'
import { version } from '../../../package.json' with { type: 'json' }
import { isAgent, isForceColor } from '../../utils/env'
import { cliOptionsConfig, collectCliOptionsConfig } from './cli-config'
import { setupTabCompletions } from './completions'

function addCommand(cli: CAC | Command, name: string, option: CLIOption<any>) {
  const commandName = option.alias || name
  let command = option.shorthand ? `-${option.shorthand}, --${commandName}` : `--${commandName}`
  if ('argument' in option) {
    command += ` ${option.argument}`
  }

  function transform(value: unknown) {
    if (!option.array && Array.isArray(value)) {
      const received = value.map(s => typeof s === 'string' ? `"${s}"` : s).join(', ')
      throw new Error(
        `Expected a single value for option "${command}", received [${received}]`,
      )
    }
    value = removeQuotes(value)
    if (option.transform) {
      return option.transform(value)
    }
    if (option.array) {
      return toArray(value)
    }
    if (option.normalize) {
      return normalize(String(value))
    }
    return value
  }

  const hasSubcommands = 'subcommands' in option && option.subcommands

View on GitHub (pinned to 1fa9837ec2)