vitest-dev/vitest · error · Error

Invalid command name

Error message

Invalid command name "${name}". Only alphanumeric characters, $ and _ are allowed.

What it means

registerCommand validates the command name with /^[a-z_$][\w$]*$/i because the name is interpolated into generated JavaScript as an identifier key inside the browser-runner context module. Names that are not valid JS identifiers would produce a syntax error in the generated code, so they are rejected up front.

Solutions

  1. Rename the command to a valid JS identifier: use camelCase (takeScreenshot) or snake_case, no hyphens/dots/spaces, no leading digit.
  2. If you need namespaces, flatten with a delimiter that is identifier-safe (underscore) e.g. 'foo_bar'.
  3. Audit every registerCommand call site and every entry in config.browser.commands for the same constraint.

Example fix

// before
registerCommand('take-screenshot', cb)
// after
registerCommand('takeScreenshot', cb)
Defensive patterns

Strategy: validation

Validate before calling

function isValidCommandName(name: string): boolean {
  return /^[a-z_$][\w$]*$/i.test(name)
}

Type guard

function isCommandName(name: unknown): name is string {
  return typeof name === 'string' && /^[a-z_$][\w$]*$/i.test(name)
}

Prevention

When it happens

Trigger: Calling projectBrowser.registerCommand('my-command', ...) with a hyphen, space, leading digit, or any non-identifier character; registering a command from a plugin using a name like 'foo.bar' or '123cmd'.

Common situations: Authoring a custom browser command whose name mirrors a CLI flag style ('take-screenshot'); importing a command from a third-party plugin that uses dotted names; copy-paste from an HTTP route name into a command registration.

Related errors


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

Appendix: source

Thrown at packages/browser/src/node/project.ts:71

    }
    this.testerFilepath = testerHtmlPath
    this.testerHtml = readFile(
      this.testerFilepath,
      'utf8',
    ).then(html => (this.testerHtml = html))
  }

  private commands = {} as Record<string, BrowserCommand<any, any>>

  public registerCommand<K extends keyof BrowserCommands>(
    name: K,
    cb: BrowserCommand<
      Parameters<BrowserCommands[K]>,
      ReturnType<BrowserCommands[K]>
    >,
  ): void {
    if (!/^[a-z_$][\w$]*$/i.test(name)) {
      throw new Error(
        `Invalid command name "${name}". Only alphanumeric characters, $ and _ are allowed.`,
      )
    }
    this.commands[name] = cb
  }

  public triggerCommand = (<K extends keyof BrowserCommand>(
    name: K,
    context: BrowserCommandContext,
    ...args: Parameters<BrowserCommands[K]>
  ): ReturnType<BrowserCommands[K]> => {
    if (name in this.commands) {
      return this.commands[name](context, ...args)
    }
    if (name in this.parent.commands) {
      return this.parent.commands[name](context, ...args)
    }
    throw new Error(`Provider ${this.provider.name} does not support command "${name}".`)

View on GitHub (pinned to 1fa9837ec2)