jackwener/OpenCLI · error

Install command is empty.

Error message

Install command is empty.

What it means

parseCommand throws when tokenising the command yields zero tokens — i.e. the command string contains no actual words (empty or whitespace/quotes only). The library cannot determine a binary to run, so it fails fast.

Source

Thrown at src/external.ts:130

export function parseCommand(cmd: string): { binary: string; args: string[] } {
  const shellOperators = /&&|\|\|?|;|[><`$#\n\r]|\$\(/;
  if (shellOperators.test(cmd)) {
    throw new Error(
      `Install command contains unsafe shell operators and cannot be executed securely: "${cmd}". ` +
        `Please install the tool manually.`
    );
  }

  // Tokenise respecting single- and double-quoted segments (no variable expansion).
  const tokens: string[] = [];
  const re = /(?:"([^"]*)")|(?:'([^']*)')|(\S+)/g;
  let match: RegExpExecArray | null;
  while ((match = re.exec(cmd)) !== null) {
    tokens.push(match[1] ?? match[2] ?? match[3]);
  }

  if (tokens.length === 0) {
    throw new Error(`Install command is empty.`);
  }

  const [binary, ...args] = tokens;
  return { binary, args };
}

function shouldRetryWithCmdShim(binary: string, err: unknown): boolean {
  const code = err instanceof Error ? (err as NodeJS.ErrnoException).code : undefined;
  return os.platform() === 'win32' && !path.extname(binary) && code === 'ENOENT';
}

function runInstallCommand(cmd: string): void {
  const { binary, args } = parseCommand(cmd);

  try {
    execFileSync(binary, args, { stdio: 'inherit' });
  } catch (err) {
    if (shouldRetryWithCmdShim(binary, err)) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Provide a non-empty install command (e.g. 'npm install -g <tool>') in the config.
  2. Trim whitespace before saving/loading the config value to avoid whitespace-only strings.
  3. If the tool cannot be auto-installed, install it manually so no install command is needed.

Example fix

// before (apps.yaml)
install: "   "
// after
install: "npm install -g mytool"
Defensive patterns

Strategy: validation

Validate before calling

if (!cmd || cmd.trim().length === 0) {
  throw new Error("Install command must be a non-empty string before calling parseCommand");
}
parseCommand(cmd);

Type guard

function isNonEmptyCommand(cmd: unknown): cmd is string {
  return typeof cmd === "string" && cmd.trim().length > 0;
}

Try / catch

try {
  const { binary } = parseCommand(cmd);
} catch (e) {
  if (e.message === "Install command is empty.") {
    console.error("No install command configured; install the tool manually.");
  }
}

Prevention

When it happens

Trigger: Calling parseCommand(''), parseCommand(' '), or a string of only quote characters; any install command whose tokenizer regex matches nothing.

Common situations: Empty installCommand field in apps.yaml or CLI registry config; config value that is only spaces; a template placeholder (${...}) that was stripped earlier by the shell-operator check leaving an empty string.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/5c7ea65ad98e5894. Report an issue: GitHub.