{"record":{"id":"baa9050b9183478b","repo":"vitest-dev/vitest","slug":"invalid-command-name-name-only-alphanumeric","errorCode":null,"errorMessage":"Invalid command name \"${name}\". Only alphanumeric characters, $ and _ are allowed.","messagePattern":"Invalid command name \"(.+?)\"\\. Only alphanumeric characters, \\$ and _ are allowed\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/node/project.ts","lineNumber":71,"sourceCode":"    }\n    this.testerFilepath = testerHtmlPath\n    this.testerHtml = readFile(\n      this.testerFilepath,\n      'utf8',\n    ).then(html => (this.testerHtml = html))\n  }\n\n  private commands = {} as Record<string, BrowserCommand<any, any>>\n\n  public registerCommand<K extends keyof BrowserCommands>(\n    name: K,\n    cb: BrowserCommand<\n      Parameters<BrowserCommands[K]>,\n      ReturnType<BrowserCommands[K]>\n    >,\n  ): void {\n    if (!/^[a-z_$][\\w$]*$/i.test(name)) {\n      throw new Error(\n        `Invalid command name \"${name}\". Only alphanumeric characters, $ and _ are allowed.`,\n      )\n    }\n    this.commands[name] = cb\n  }\n\n  public triggerCommand = (<K extends keyof BrowserCommand>(\n    name: K,\n    context: BrowserCommandContext,\n    ...args: Parameters<BrowserCommands[K]>\n  ): ReturnType<BrowserCommands[K]> => {\n    if (name in this.commands) {\n      return this.commands[name](context, ...args)\n    }\n    if (name in this.parent.commands) {\n      return this.parent.commands[name](context, ...args)\n    }\n    throw new Error(`Provider ${this.provider.name} does not support command \"${name}\".`)","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser/src/node/project.ts#L53-L89","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","solutions":["Rename the command to a valid JS identifier: use camelCase (takeScreenshot) or snake_case, no hyphens/dots/spaces, no leading digit.","If you need namespaces, flatten with a delimiter that is identifier-safe (underscore) e.g. 'foo_bar'.","Audit every registerCommand call site and every entry in config.browser.commands for the same constraint."],"exampleFix":"// before\nregisterCommand('take-screenshot', cb)\n// after\nregisterCommand('takeScreenshot', cb)","handlingStrategy":"validation","validationCode":"function isValidCommandName(name: string): boolean {\n  return /^[a-z_$][\\w$]*$/i.test(name)\n}","typeGuard":"function isCommandName(name: unknown): name is string {\n  return typeof name === 'string' && /^[a-z_$][\\w$]*$/i.test(name)\n}","tryCatchPattern":null,"preventionTips":["Use camelCase for all command names.","Add a unit test that asserts every registerCommand call passes the identifier regex.","Avoid copy-pasting REST/CLI route names into command registrations."],"tags":["browser-command","validation","identifier","config"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}