headroomlabs-ai/headroom · error · KeyError
unknown tool {tool!r}
Error message
unknown tool {tool!r} What it means
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.
Source
Thrown at headroom/binaries.py:455
_asset_for_platform(tool, plat) # raises if unsupported
except PlatformNotSupported:
return None
path = _cached_path(tool, _tool_entry(tool)["version"], plat)
return path if path.exists() else None
def resolve(tool: str) -> Path:
"""Return a path to the tool binary, fetching it on first use.
Raises PlatformNotSupported if the tool is unavailable on this platform,
OfflineError if a fetch is required but HEADROOM_BINARIES_OFFLINE is set,
Sha256Mismatch if verification fails, BinaryFetchError on other IO errors.
"""
on_path = _path_lookup(tool)
if on_path:
return on_path
if not _in_registry(tool):
raise KeyError(f"unknown tool {tool!r}")
plat = detect_platform()
entry = _tool_entry(tool)
asset = _asset_for_platform(tool, plat)
version = entry["version"]
binary_path = _cached_path(tool, version, plat)
if binary_path.exists():
return binary_path
# Not cached — fetch, verify, extract.
url = asset["url"]
sha256 = asset.get("sha256")
member = asset.get("member", _binary_name(tool, plat))
with tempfile.TemporaryDirectory(prefix="headroom-fetch-") as tmp:
tmp_dir = Path(tmp)
# Strip query params so mirror URLs like `.../difft.tar.gz?token=...`
# don't produce filenames that break archive-type detection.View on GitHub (pinned to 322425c43b)
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
Example fix
# before
path = binaries.resolve("ripgrep") # KeyError: unknown tool 'ripgrep'
# after
path = binaries.which("ripgrep")
if path is None:
path = shutil.which("rg") or _install_or_fail() Defensive patterns
Strategy: validation
Validate before calling
from headroom import binaries
if not binaries._in_registry(tool) and not shutil.which(tool):
raise SystemExit(f"tool {tool!r} unavailable; install it or use a registry name")
path = binaries.resolve(tool) Type guard
def resolvable(tool: str) -> bool:
from headroom import binaries
return binaries.which(tool) is not None or binaries._in_registry(tool) Try / catch
try:
path = binaries.resolve(tool)
except KeyError as e:
# unknown tool name — surface to caller or pick an alternative
log.warning("unknown tool %s", tool) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- archive did not contain expected member {member!r}
- No optimizer registered for '{key}'. Available: {available}
- unknown tool {tool!r}; known: {sorted(tools)}
- {tool}: distributed via PyPI only; `pip install headroom-ai`
- {tool}: no prebuilt binary for {plat.key()}; supported: {sup
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/25c85c718895c42e.
Report an issue: GitHub.