{"record":{"id":"d664878a51da6d1b","repo":"can1357/oh-my-pi","slug":"unknown-tool-tool","errorCode":null,"errorMessage":"Unknown tool: ${tool}","messagePattern":"Unknown tool: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/utils/tools-manager.ts","lineNumber":220,"sourceCode":"\t\t});\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to download: ${response.status}`);\n\t\t} else if (!response.body) {\n\t\t\tthrow new Error(\"No response body\");\n\t\t}\n\t\tawait writeResponseBody(dest, response.body, downloadSignal);\n\t} catch (err) {\n\t\tif (isAbortLikeError(err)) {\n\t\t\tthrow new Error(`Download timed out: ${url}`);\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n// Download and install a tool\nasync function downloadTool(tool: ToolName, signal?: AbortSignal): Promise<string> {\n\tconst config = TOOLS[tool];\n\tif (!config) throw new Error(`Unknown tool: ${tool}`);\n\n\tconst plat = os.platform();\n\tconst architecture = os.arch();\n\n\t// Get latest version\n\tconst version = await getLatestVersion(config.repo, signal);\n\n\t// Get asset name for this platform\n\tconst assetName = config.getAssetName(version, plat, architecture);\n\tif (!assetName) {\n\t\tthrow new Error(`Unsupported platform: ${plat}/${architecture}`);\n\t}\n\n\t// Create tools directory\n\tawait fs.promises.mkdir(TOOLS_DIR, { recursive: true });\n\n\tconst downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;\n\tconst binaryExt = plat === \"win32\" ? \".exe\" : \"\";","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/utils/tools-manager.ts#L202-L238","documentation":"downloadTool() looks up the tool's metadata in the TOOLS registry before doing any network work. If the requested name is not a registered ToolName, it throws immediately with the unknown name — a guard against programming errors rather than an environmental failure.","triggerScenarios":"Calling downloadTool/path/download with a tool name not present in the TOOLS map, e.g. a typo (\"ripgrep\" instead of \"rg\") or a tool added upstream but not in this version of the manager.","commonSituations":"Typos in tool identifiers, code written against a newer/older tool list, dynamic tool names derived from user input or config files containing an unsupported entry.","solutions":["Fix the tool name to one of the supported ToolName values defined in TOOLS.","If using dynamic/config-driven names, validate against the known tool list before calling.","Upgrade the package if the tool was added in a newer version of the manager.","Install the missing tool manually and reference it via its system path instead."],"exampleFix":"// before: await toolsManager.path(\"ripgrep\") // throws Unknown tool: ripgrep | // after: await toolsManager.path(\"rg\") // correct registered name","handlingStrategy":"validation","validationCode":"// validate the tool name against the registry before calling | const SUPPORTED = new Set([\"rg\", \"fd\", \"sg\", \"ast-grep\"]); if (!SUPPORTED.has(toolName)) throw new Error(`Unsupported tool: ${toolName}`);","typeGuard":"function isKnownTool(name: string): name is ToolName { return ([\"rg\", \"fd\", \"sg\", \"ast-grep\"] as string[]).includes(name); }","tryCatchPattern":"try { const p = await toolsManager.path(toolName); } catch (err) { if (err.message.startsWith(\"Unknown tool:\")) { /* reject the config entry / prompt user for a valid tool */ } else throw err; }","preventionTips":["Use the exported ToolName type instead of raw strings.","Validate config/user-supplied tool names against the registry at load time.","Keep the tool list in sync when upgrading the package.","Centralize tool-name constants to avoid typos."],"tags":["configuration","invalid-argument"],"backgroundTag":"unknown-tool-name","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}