{"record":{"id":"25c85c718895c42e","repo":"headroomlabs-ai/headroom","slug":"unknown-tool-tool-r","errorCode":null,"errorMessage":"unknown tool {tool!r}","messagePattern":"unknown tool (.+?)","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"headroom/binaries.py","lineNumber":455,"sourceCode":"        _asset_for_platform(tool, plat)  # raises if unsupported\n    except PlatformNotSupported:\n        return None\n    path = _cached_path(tool, _tool_entry(tool)[\"version\"], plat)\n    return path if path.exists() else None\n\n\ndef resolve(tool: str) -> Path:\n    \"\"\"Return a path to the tool binary, fetching it on first use.\n\n    Raises PlatformNotSupported if the tool is unavailable on this platform,\n    OfflineError if a fetch is required but HEADROOM_BINARIES_OFFLINE is set,\n    Sha256Mismatch if verification fails, BinaryFetchError on other IO errors.\n    \"\"\"\n    on_path = _path_lookup(tool)\n    if on_path:\n        return on_path\n    if not _in_registry(tool):\n        raise KeyError(f\"unknown tool {tool!r}\")\n\n    plat = detect_platform()\n    entry = _tool_entry(tool)\n    asset = _asset_for_platform(tool, plat)\n    version = entry[\"version\"]\n    binary_path = _cached_path(tool, version, plat)\n    if binary_path.exists():\n        return binary_path\n\n    # Not cached — fetch, verify, extract.\n    url = asset[\"url\"]\n    sha256 = asset.get(\"sha256\")\n    member = asset.get(\"member\", _binary_name(tool, plat))\n\n    with tempfile.TemporaryDirectory(prefix=\"headroom-fetch-\") as tmp:\n        tmp_dir = Path(tmp)\n        # Strip query params so mirror URLs like `.../difft.tar.gz?token=...`\n        # don't produce filenames that break archive-type detection.","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/binaries.py#L437-L473","documentation":"headroom.binaries.resolve(tool) resolves a tool binary three ways: PATH lookup, the built-in download registry, then failure. The KeyError 'unknown tool' is raised only when the tool is neither found on PATH (or the interpreter's Scripts/bin dir) nor present in headroom's bundled tool registry (_registry()['tools']). It means headroom has no way to obtain this binary at all.","triggerScenarios":"Calling resolve() with a misspelled or unregistered tool name (e.g. resolve('astgrep') instead of 'ast-grep'), or with a tool headroom simply does not manage, while the tool is also absent from PATH and from sys.prefix/bin|Scripts.","commonSituations":"Typos in tool names; assuming headroom can fetch any arbitrary tool; running inside a venv where the tool's console script lives in an interpreter directory not checked; newer headroom versions that renamed registry keys.","solutions":["Install the tool on PATH (pip/npm/brew/apt) so _path_lookup() succeeds before the registry check","Check the exact registry key: python -c \"from headroom.binaries import _registry; print(list(_registry()['tools']))\" and use that name","Fix typos — registry names are exact, e.g. 'ast-grep' not 'astgrep'","Use headroom.binaries.which(tool) first if you want a None instead of an exception for unknown tools"],"exampleFix":"# before\npath = binaries.resolve(\"ripgrep\")  # KeyError: unknown tool 'ripgrep'\n\n# after\npath = binaries.which(\"ripgrep\")\nif path is None:\n    path = shutil.which(\"rg\") or _install_or_fail()","handlingStrategy":"validation","validationCode":"from headroom import binaries\nif not binaries._in_registry(tool) and not shutil.which(tool):\n    raise SystemExit(f\"tool {tool!r} unavailable; install it or use a registry name\")\npath = binaries.resolve(tool)","typeGuard":"def resolvable(tool: str) -> bool:\n    from headroom import binaries\n    return binaries.which(tool) is not None or binaries._in_registry(tool)","tryCatchPattern":"try:\n    path = binaries.resolve(tool)\nexcept KeyError as e:\n    # unknown tool name — surface to caller or pick an alternative\n    log.warning(\"unknown tool %s\", tool)","preventionTips":["Derive tool names from binaries._registry()['tools'].keys() instead of hardcoding strings","Use binaries.which() for probe-style checks — it returns None instead of raising","CI: assert all required tools resolve before starting the test suite"],"tags":["binaries","registry","path-lookup","keyerror"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}