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

  1. Inspect the stack trace to find which caller passed the empty command (runPackageManagerInstallCommand, hasPackageManager, or runGitCloneCommand) and check the value it computed.
  2. If reached via git clone, verify the gitStrategy in packages/create-docusaurus/src/commands.ts getGitCloneCommand returns a non-empty string for every case.
  3. If reached via package-manager install, verify the installCommand ternary in runPackageManagerInstallCommand never produces an empty string for the active PackageManager.
  4. 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

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


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/c0ecb6517a6fa352. Report an issue: GitHub.