{"record":{"id":"d250dcc75df0206c","repo":"jackwener/OpenCLI","slug":"external-cli-name-not-found-in-registry","errorCode":null,"errorMessage":"External CLI '${name}' not found in registry.","messagePattern":"External CLI '(.+?)' not found in registry\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/external.ts","lineNumber":186,"sourceCode":"  }\n\n  log.info(`'${cli.name}' is not installed. Auto-installing...`);\n  log.verbose(`$ ${cmd}`);\n  try {\n    runInstallCommand(cmd);\n    log.success(`Installed '${cli.name}' successfully.`);\n    return true;\n  } catch (err) {\n    log.error(`Failed to install '${cli.name}': ${getErrorMessage(err)}`);\n    return false;\n  }\n}\n\nexport function executeExternalCli(name: string, args: string[], preloaded?: ExternalCliConfig[]): void {\n  const configs = preloaded ?? loadExternalClis();\n  const cli = configs.find((c) => c.name === name);\n  if (!cli) {\n    throw new Error(`External CLI '${name}' not found in registry.`);\n  }\n\n  // 1. Check if installed\n  if (!isBinaryInstalled(cli.binary)) {\n    // 2. Try to auto install\n    const success = installExternalCli(cli);\n    if (!success) {\n      process.exitCode = EXIT_CODES.SERVICE_UNAVAIL;\n      return;\n    }\n  }\n\n  // 3. Passthrough execution with stdio inherited\n  const result = spawnPassthrough(cli.binary, args);\n  if (result.error) {\n    log.error(`Failed to execute '${cli.binary}': ${result.error.message}`);\n    process.exitCode = EXIT_CODES.GENERIC_ERROR;\n    return;","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/src/external.ts#L168-L204","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the exact registered name (list the registry / loadExternalClis output) and correct the name, matching case exactly.","Add the tool to the registry config file that loadExternalClis reads, with name, binary, and install command fields.","If a preloaded list is passed, verify it actually contains the CLI you are invoking."],"exampleFix":"// before\nexecuteExternalCli(\"git-leaks\", [\"detect\"]);\n// after (if registry entry is named 'gitleaks')\nexecuteExternalCli(\"gitleaks\", [\"detect\"]);","handlingStrategy":"validation","validationCode":"const configs = loadExternalClis();\nif (!configs.some((c) => c.name === name)) {\n  throw new Error(`'${name}' not registered. Known: ${configs.map((c) => c.name).join(\", \")}`);\n}\nexecuteExternalCli(name, args);","typeGuard":"function isRegistered(name: string, configs: ExternalCliConfig[]): boolean {\n  return configs.some((c) => c.name === name);\n}","tryCatchPattern":"try {\n  executeExternalCli(name, args);\n} catch (e) {\n  if (/not found in registry/.test(e.message)) {\n    console.error(`Unknown CLI '${name}'. Add it to the registry or fix the name.`);\n  }\n}","preventionTips":["Keep a single source of truth for CLI names and import/derive names from it.","Use exact-match constants instead of hand-typed strings when invoking.","Validate config files against a schema listing required registry entries."],"tags":["config","registry","not-found"],"backgroundTag":"unknown-tool-name","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}