jackwener/OpenCLI · error

External CLI '${name}' not found in registry.

Error message

External CLI '${name}' not found in registry.

What it means

executeExternalCli looks up the requested tool name in the registry loaded by loadExternalClis (or the preloaded list). If no config with that exact name exists, it throws because there is no binary or install strategy to fall back on.

Source

Thrown at src/external.ts:186

  }

  log.info(`'${cli.name}' is not installed. Auto-installing...`);
  log.verbose(`$ ${cmd}`);
  try {
    runInstallCommand(cmd);
    log.success(`Installed '${cli.name}' successfully.`);
    return true;
  } catch (err) {
    log.error(`Failed to install '${cli.name}': ${getErrorMessage(err)}`);
    return false;
  }
}

export function executeExternalCli(name: string, args: string[], preloaded?: ExternalCliConfig[]): void {
  const configs = preloaded ?? loadExternalClis();
  const cli = configs.find((c) => c.name === name);
  if (!cli) {
    throw new Error(`External CLI '${name}' not found in registry.`);
  }

  // 1. Check if installed
  if (!isBinaryInstalled(cli.binary)) {
    // 2. Try to auto install
    const success = installExternalCli(cli);
    if (!success) {
      process.exitCode = EXIT_CODES.SERVICE_UNAVAIL;
      return;
    }
  }

  // 3. Passthrough execution with stdio inherited
  const result = spawnPassthrough(cli.binary, args);
  if (result.error) {
    log.error(`Failed to execute '${cli.binary}': ${result.error.message}`);
    process.exitCode = EXIT_CODES.GENERIC_ERROR;
    return;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check the exact registered name (list the registry / loadExternalClis output) and correct the name, matching case exactly.
  2. Add the tool to the registry config file that loadExternalClis reads, with name, binary, and install command fields.
  3. If a preloaded list is passed, verify it actually contains the CLI you are invoking.

Example fix

// before
executeExternalCli("git-leaks", ["detect"]);
// after (if registry entry is named 'gitleaks')
executeExternalCli("gitleaks", ["detect"]);
Defensive patterns

Strategy: validation

Validate before calling

const configs = loadExternalClis();
if (!configs.some((c) => c.name === name)) {
  throw new Error(`'${name}' not registered. Known: ${configs.map((c) => c.name).join(", ")}`);
}
executeExternalCli(name, args);

Type guard

function isRegistered(name: string, configs: ExternalCliConfig[]): boolean {
  return configs.some((c) => c.name === name);
}

Try / catch

try {
  executeExternalCli(name, args);
} catch (e) {
  if (/not found in registry/.test(e.message)) {
    console.error(`Unknown CLI '${name}'. Add it to the registry or fix the name.`);
  }
}

Prevention

When it happens

Trigger: Calling executeExternalCli(name, args) or passthroughExternal with a name that does not exactly match any c.name in loadExternalClis() output, e.g. a typo or a tool not present in the registry config file.

Common situations: Typo in CLI name ('gitleaks' vs 'git-leaks'); registry file missing the tool entry; casing mismatch since lookup is exact; config file at a different path than the one the library reads.

Related errors


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