headroomlabs-ai/headroom · error · BinaryFetchError

failed to download {final_url} after {attempts} attempts: {e

Error message

failed to download {final_url} after {attempts} attempts: {e}

What it means

_download retries each urllib.error.URLError up to 3 times (linear backoff 0.25s * attempt) because GitHub release assets intermittently 5xx or reset during the redirect to the object store. If the final attempt still fails, BinaryFetchError is raised with the (mirror-substituted) final URL and the underlying exception chained via 'from e'. Persistent failures — DNS, proxy, auth, mirror misconfig — are never masked by the retry.

Source

Thrown at headroom/binaries.py:259

        raise OfflineError(f"offline mode (HEADROOM_BINARIES_OFFLINE=1) but fetch required: {url}")
    if not _has_writable_existing_parent(dest.parent):
        raise OSError(f"binary cache directory parent is not writable: {dest.parent}")
    dest.parent.mkdir(parents=True, exist_ok=True)
    if not _is_writable_dir(dest.parent):
        raise OSError(f"binary cache directory is not writable: {dest.parent}")
    final_url = _mirror_url(url)
    req = urllib.request.Request(final_url, headers={"User-Agent": "headroom-binaries/1"})
    attempts = 3
    for attempt in range(1, attempts + 1):
        try:
            with urllib.request.urlopen(req, timeout=60) as resp:  # noqa: S310 (https)
                total = int(resp.headers.get("Content-Length") or 0)
                _stream_to(resp, dest, total, label=dest.name, show_progress=progress)
            return
        except urllib.error.URLError as e:
            dest.unlink(missing_ok=True)
            if attempt == attempts:
                raise BinaryFetchError(
                    f"failed to download {final_url} after {attempts} attempts: {e}"
                ) from e
            # GitHub release assets occasionally return a transient 5xx or
            # reset while redirecting to the object store. A short bounded
            # retry keeps proxy startup reliable without hiding persistent
            # credential, mirror, or connectivity failures.
            time.sleep(0.25 * attempt)


def _stream_to(src: Any, dest: Path, total: int, *, label: str, show_progress: bool) -> None:
    # Rich progress if available and stderr is a tty; otherwise silent chunked copy.
    try:
        if show_progress and sys.stderr.isatty():
            from rich.progress import (
                BarColumn,
                DownloadColumn,
                Progress,
                TextColumn,

View on GitHub (pinned to 322425c43b)

Solutions

  1. Read the chained '{e}' — 'Name or service not known' means DNS, '407/403' means proxy/auth, 'CERTIFICATE_VERIFY_FAILED' means TLS interception.
  2. If direct GitHub is blocked, set HEADROOM_BINARIES_MIRROR to an internal mirror that serves the same path layout (only github.com and objects.githubusercontent.com prefixes are rewritten).
  3. Allow egress to github.com and objects.githubusercontent.com in firewall/proxy rules.
  4. If TLS interception is the cause, install the corporate CA into the image trust store.

Example fix

# before
ENV HEADROOM_BINARIES_MIRROR=https://artifacts.internal/gh  # 404s -> BinaryFetchError

# after
# mirror must serve the same path layout as github.com releases:
ENV HEADROOM_BINARIES_MIRROR=https://artifacts.internal/github-mirror
Defensive patterns

Strategy: retry

Validate before calling

import socket, urllib.request

def github_reachable() -> bool:
    for host in ("github.com", "objects.githubusercontent.com"):
        try:
            urllib.request.urlopen(f"https://{host}", timeout=5)
        except urllib.error.URLError:
            return False
    return True

if not github_reachable() and not os.environ.get("HEADROOM_BINARIES_MIRROR"):
    raise SystemExit("no egress to GitHub; set HEADROOM_BINARIES_MIRROR to an internal mirror")

Try / catch

from headroom.binaries import BinaryFetchError

for attempt in range(2):
    try:
        ensure_binary(tool)
        break
    except BinaryFetchError as e:
        if attempt == 1:
            raise SystemExit(f"persistent fetch failure: {e}; check proxy/mirror/egress") from e
        time.sleep(5)  # outer retry only for transient infra blips

Prevention

When it happens

Trigger: Any URLError persisting across 3 attempts: no network egress, corporate proxy blocking github.com/objects.githubusercontent.com, HEADROOM_BINARIES_MIRROR pointing at a dead endpoint, or TLS interception failures.

Common situations: CI runners without GitHub egress, air-gapped clusters with an incorrectly configured internal mirror URL, corporate SSL-inspection proxies breaking the asset redirect chain.

Related errors


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