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

  1. Install the tool on PATH (pip/npm/brew/apt) so _path_lookup() succeeds before the registry check
  2. Check the exact registry key: python -c "from headroom.binaries import _registry; print(list(_registry()['tools']))" and use that name
  3. Fix typos — registry names are exact, e.g. 'ast-grep' not 'astgrep'
  4. 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

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


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/25c85c718895c42e. Report an issue: GitHub.