{"record":{"id":"c0ecb6517a6fa352","repo":"facebook/docusaurus","slug":"invalid-command-command","errorCode":null,"errorMessage":"Invalid command: ${command}","messagePattern":"Invalid command: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/create-docusaurus/src/commands.ts","lineNumber":43,"sourceCode":"/**\n * Run a command, similar to execa(cmd,args) but simpler\n * @param command\n * @param args\n * @param options\n * @returns the command exit code\n */\nasync function runCommand(\n  command: string,\n  args: string[] = [],\n  options: SpawnOptions = {},\n): Promise<number> {\n  // This does something similar to execa.command()\n  // we split a string command (with optional args) into command+args\n  // this way it's compatible with spawn()\n  const [realCommand, ...baseArgs] = command.split(' ');\n  const allArgs = [...baseArgs, ...args];\n  if (!realCommand) {\n    throw new Error(`Invalid command: ${command}`);\n  }\n\n  return new Promise<number>((resolve, reject) => {\n    const p = crossSpawn(realCommand, allArgs, {stdio: 'ignore', ...options});\n    p.on('error', reject);\n    p.on('close', (exitCode) =>\n      exitCode !== null\n        ? resolve(exitCode)\n        : reject(new Error(`No exit code for command ${command}`)),\n    );\n  });\n}\n\nasync function hasPackageManager(\n  packageManager: PackageManager,\n): Promise<boolean> {\n  return (await runCommand(packageManager, ['--version'])) === 0;\n}","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/facebook/docusaurus/blob/3f483e80e326cc646b54b83d564b3f0c4881b9a6/packages/create-docusaurus/src/commands.ts#L25-L61","documentation":"Thrown by the internal runCommand() helper in create-docusaurus when a command string splits on spaces and yields no leading token (i.e. the first segment is empty or all whitespace). runCommand wraps cross-spawn to run package-manager install, version checks, and git clone, so it needs a resolvable executable name. An empty/whitespace-only command cannot be spawned, so it is rejected before any process is forked. This is almost always an internal-programming or constants-table defect, not a user input.","triggerScenarios":"Calling runCommand('') (empty string), runCommand('   ') (whitespace only), or runCommand(' arg') (leading space, first segment empty). Reached indirectly via runPackageManagerInstallCommand, hasPackageManager('--version'), or runGitCloneCommand when the gitStrategy branch in getGitCloneCommand returns an empty string.","commonSituations":"A refactor of getGitCloneCommand that adds a new GitCloneStrategy case but forgets to return a command string; a constants table that accidentally maps a package manager to an empty install command; a future gitStrategy value that falls through the switch without a default return.","solutions":["Inspect the stack trace to find which caller passed the empty command (runPackageManagerInstallCommand, hasPackageManager, or runGitCloneCommand) and check the value it computed.","If reached via git clone, verify the gitStrategy in packages/create-docusaurus/src/commands.ts getGitCloneCommand returns a non-empty string for every case.","If reached via package-manager install, verify the installCommand ternary in runPackageManagerInstallCommand never produces an empty string for the active PackageManager.","Add a unit test asserting runCommand rejects empty input and that every GitCloneStrategy resolves to a non-empty command."],"exampleFix":"// before (switch with a fall-through case returning '')\ncase 'custom':\n  return '';\n// after\ncase 'custom':\n  return askForCustomGitCloneCommand();","handlingStrategy":"validation","validationCode":"function assertCommand(command: string): void {\n  if (!command || !command.trim()) {\n    throw new Error(`Invalid command: ${JSON.stringify(command)}`);\n  }\n}\n// call before runCommand:\nassertCommand(cmd);","typeGuard":"const isNonEmptyCommand = (c: unknown): c is string =>\n  typeof c === 'string' && c.trim().length > 0 && c.split(' ')[0]!.trim() !== '';","tryCatchPattern":null,"preventionTips":["Never construct command strings from optional fields without a default (e.g. getGitCloneCommand must return for every strategy).","Add a unit test that every GitCloneStrategy and PackageManager resolves to a non-empty command.","Treat an empty command as a programmer error and fail loud at the call site, not inside cross-spawn."],"tags":["create-docusaurus","spawn","internal-bug","validation"],"backgroundTag":null,"analyzedSha":"3f483e80e326cc646b54b83d564b3f0c4881b9a6","analyzedAt":"2026-08-12T13:25:04.382Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}