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
- Read the chained '{e}' — 'Name or service not known' means DNS, '407/403' means proxy/auth, 'CERTIFICATE_VERIFY_FAILED' means TLS interception.
- 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).
- Allow egress to github.com and objects.githubusercontent.com in firewall/proxy rules.
- 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
- Open egress to github.com and objects.githubusercontent.com (or configure a mirror with identical paths).
- The internal retry is only 3 quick attempts; do not rely on it for flaky networks — add health monitoring.
- Verify corporate proxies allow the release-asset redirect chain, not just the initial request.
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
- sha256 mismatch for {path.name}: expected {expected}, got {g
- {tool}: distributed via PyPI only; `pip install headroom-ai`
- {tool}: no prebuilt binary for {plat.key()}; supported: {sup
- offline mode (HEADROOM_BINARIES_OFFLINE=1) but fetch require
- binary cache directory parent is not writable: {dest.parent}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/388a81bd46a2b4a0.
Report an issue: GitHub.