headroomlabs-ai/headroom · error · OfflineError
offline mode (HEADROOM_BINARIES_OFFLINE=1) but fetch require
Error message
offline mode (HEADROOM_BINARIES_OFFLINE=1) but fetch required: {url} What it means
_download raises OfflineError when the HEADROOM_BINARIES_OFFLINE env var is truthy-set but the requested binary is not in the local cache, forcing a network fetch. This is an intentional air-gapped-mode guard: offline mode must never silently reach the network, so a cache miss becomes a hard error naming the URL that would have been fetched.
Source
Thrown at headroom/binaries.py:241
def _mirror_url(url: str) -> str:
mirror = os.environ.get("HEADROOM_BINARIES_MIRROR")
if not mirror:
return url
# Only substitute the github.com host so that paths remain intact.
for prefix in ("https://github.com", "https://objects.githubusercontent.com"):
if url.startswith(prefix):
return mirror.rstrip("/") + url[len(prefix) :]
return url
# ---------- Download + verify --------------------------------------------- #
def _download(url: str, dest: Path, *, progress: bool = True) -> None:
if os.environ.get("HEADROOM_BINARIES_OFFLINE"):
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(View on GitHub (pinned to 322425c43b)
Solutions
- Warm the cache during image build with the same tool set, with the env var unset: RUN headroom ... (or the project's prefetch command), then set HEADROOM_BINARIES_OFFLINE=1 at runtime.
- If the network is actually available, unset the variable: HEADROOM_BINARIES_OFFLINE= (or remove it from the deployment spec).
- Point HEADROOM_BINARIES_MIRROR at an internal mirror and drop offline mode if direct GitHub access is the reason it was enabled.
Example fix
# before (Dockerfile) ENV HEADROOM_BINARIES_OFFLINE=1 RUN headroom doctor # OfflineError: cache empty # after (Dockerfile) RUN headroom doctor # downloads and populates cache ENV HEADROOM_BINARIES_OFFLINE=1
Defensive patterns
Strategy: validation
Validate before calling
import os
def offline_cache_complete(urls_or_tools: list[str]) -> bool:
if not os.environ.get("HEADROOM_BINARIES_OFFLINE"):
return True
cache = binaries_cache_dir() # wherever the runtime caches fetched tools
return all((cache / t).exists() for t in urls_or_tools)
assert offline_cache_complete(["difft", "scc"]), "warm the cache before enabling offline mode" Try / catch
try:
ensure_binary(tool)
except OfflineError as e:
raise SystemExit(f"offline mode set but {tool} not cached; run the prefetch step in the image build") from e Prevention
- Warm the binary cache at image build time, then enable HEADROOM_BINARIES_OFFLINE at runtime.
- Persist the cache in a volume so ephemeral containers do not start cold.
- Add a CI job that builds the offline image and smoke-tests tool startup.
When it happens
Trigger: HEADROOM_BINARIES_OFFLINE=1 (or any non-empty value) + first use of a tool on that machine/container, or after the cache directory was cleared.
Common situations: Air-gapped or CI environments where offline mode is set for reproducibility but the image was never warmed with a pre-fetch step; k8s emptyDir or ephemeral containers losing the cache between runs.
Related errors
- {tool}: distributed via PyPI only; `pip install headroom-ai`
- {tool}: no prebuilt binary for {plat.key()}; supported: {sup
- binary cache directory parent is not writable: {dest.parent}
- binary cache directory is not writable: {dest.parent}
- failed to download {final_url} after {attempts} attempts: {e
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/dfe7afbe1fe9a555.
Report an issue: GitHub.