facebook/docusaurus · error · Error
Invalid command: ${command}
Error message
Invalid command: ${command} What it means
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.
Source
Thrown at packages/create-docusaurus/src/commands.ts:43
/**
* Run a command, similar to execa(cmd,args) but simpler
* @param command
* @param args
* @param options
* @returns the command exit code
*/
async function runCommand(
command: string,
args: string[] = [],
options: SpawnOptions = {},
): Promise<number> {
// This does something similar to execa.command()
// we split a string command (with optional args) into command+args
// this way it's compatible with spawn()
const [realCommand, ...baseArgs] = command.split(' ');
const allArgs = [...baseArgs, ...args];
if (!realCommand) {
throw new Error(`Invalid command: ${command}`);
}
return new Promise<number>((resolve, reject) => {
const p = crossSpawn(realCommand, allArgs, {stdio: 'ignore', ...options});
p.on('error', reject);
p.on('close', (exitCode) =>
exitCode !== null
? resolve(exitCode)
: reject(new Error(`No exit code for command ${command}`)),
);
});
}
async function hasPackageManager(
packageManager: PackageManager,
): Promise<boolean> {
return (await runCommand(packageManager, ['--version'])) === 0;
}View on GitHub (pinned to 3f483e80e3)
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.
Example fix
// before (switch with a fall-through case returning '') case 'custom': return ''; // after case 'custom': return askForCustomGitCloneCommand();
Defensive patterns
Strategy: validation
Validate before calling
function assertCommand(command: string): void {
if (!command || !command.trim()) {
throw new Error(`Invalid command: ${JSON.stringify(command)}`);
}
}
// call before runCommand:
assertCommand(cmd); Type guard
const isNonEmptyCommand = (c: unknown): c is string =>
typeof c === 'string' && c.trim().length > 0 && c.split(' ')[0]!.trim() !== ''; Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid package manager choice ${packageManager}. Must be on
- Directory already exists at path=${dest}!
- Copying Docusaurus template name=${source.template.name} fai
- Copying local template path=${source.path} failed!
- Failed to update package.json.
AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12).
Data as JSON: /api/errors/c0ecb6517a6fa352.
Report an issue: GitHub.