{"record":{"id":"650b9e50061a8112","repo":"vitest-dev/vitest","slug":"invalid-command-name-command-only-alphanumer","errorCode":null,"errorMessage":"Invalid command name \"${command}\". 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/projectParent.ts","lineNumber":118,"sourceCode":"        }\n        // some browsers (looking at you, safari) don't report queries in stack traces\n        // the next best thing is to try the first id that this file resolves to\n        const files = moduleGraph.getModulesByFile(resolvedPath)\n        if (files && files.size) {\n          return files.values().next().value!.id!\n        }\n        return id\n      },\n    }\n\n    for (const [name, command] of Object.entries(builtinCommands)) {\n      this.commands[name] ??= command\n    }\n\n    // validate names because they can't be used as identifiers\n    for (const command in this.config.browser.commands) {\n      if (!/^[a-z_$][\\w$]*$/i.test(command)) {\n        throw new Error(\n          `Invalid command name \"${command}\". Only alphanumeric characters, $ and _ are allowed.`,\n        )\n      }\n      this.commands[command] = this.config.browser.commands[command]\n    }\n\n    this.prefixTesterUrl = `${base || '/'}`\n    this.prefixOrchestratorUrl = `${base}__vitest_test__/`\n    this.faviconUrl = `${base}__vitest__/favicon.svg`\n\n    this.manifest = (async () => {\n      return JSON.parse(\n        await readFile(`${distRoot}/client/.vite/manifest.json`, 'utf8'),\n      )\n    })().then(manifest => (this.manifest = manifest))\n\n    this.orchestratorHtml = (this.config.browser.ui\n      ? readFile(resolve(uiClientRoot, 'index.html'), 'utf8')","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser/src/node/projectParent.ts#L100-L136","documentation":"projectParent iterates config.browser.commands (user-defined commands) and validates each name with the same identifier regex as registerCommand, because those names are emitted as JS identifier keys in the tester context. Invalid names are rejected at parent setup time, before any test runs.","triggerScenarios":"Defining browser.commands in vitest.config with a hyphenated or otherwise non-identifier key, e.g. commands: { 'my-cmd': (...) => ... }; using a quoted property name that contains a dot or space.","commonSituations":"Copy-pasting REST route names into browser.commands; naming commands after CLI flags; coming from a framework where hyphenated command names are conventional.","solutions":["Rename the command key to a valid identifier (camelCase or snake_case).","Update every browser.commands.<name>() call site to match the new name.","Lint the config at startup by asserting the regex against each key."],"exampleFix":"// before\nexport default defineConfig({ test: { browser: { commands: { 'my-cmd': ctx => 1 } } } })\n// after\nexport default defineConfig({ test: { browser: { commands: { myCmd: ctx => 1 } } } })","handlingStrategy":"validation","validationCode":"function validateCommandConfig(commands: Record<string, unknown>): string[] {\n  return Object.keys(commands).filter(k => !/^[a-z_$][\\w$]*$/i.test(k))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Lint config.browser.commands keys at startup.","Use camelCase or snake_case for command keys.","Add a CI check that fails the build on invalid command names."],"tags":["browser-command","validation","identifier","config","startup"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}