NousResearch/hermes-agent · error · RuntimeError
Failed to download {url}: {exc}
Error message
Failed to download {url}: {exc} What it means
The release asset download uses urllib with a plain Request; any urllib.error.URLError (DNS failure, connection refused, TLS error, HTTP 404 surfaced as URLError) is wrapped into this RuntimeError with the failing URL. It fires during the lazy auto-install path, before any checksum or extraction work.
Source
Thrown at agent/proxy_sources/iron_proxy.py:556
# Invalidate the version cache so a freshly-installed binary
# re-probes ``--version`` on the next ``get_status()`` call instead
# of returning the pre-upgrade string. Long-lived processes that
# bump the pinned version via ``force=True`` need this.
_VERSION_CACHE.pop(str(target), None)
logger.info("Installed iron-proxy %s at %s", _IRON_PROXY_VERSION, target)
return target
def _http_download(url: str, dest: Path) -> None:
req = urllib.request.Request(url, headers={"User-Agent": "hermes-agent"})
try:
with urllib.request.urlopen(req, timeout=_DOWNLOAD_TIMEOUT) as resp: # noqa: S310
with open(dest, "wb") as f:
shutil.copyfileobj(resp, f)
except urllib.error.URLError as exc:
raise RuntimeError(f"Failed to download {url}: {exc}") from exc
def _verify_checksums_signature(tmp: Path, checksum_path: Path) -> bool:
"""Best-effort GPG verification of ``checksums.txt`` (maxpetrusenko P1).
Downloads the detached signature (``checksums.txt.asc``) and the release
signing key (``public-key.asc``), imports the key into an ephemeral
keyring, and verifies the signature over ``checksum_path``.
Returns True when the signature is verified. Returns False (with a warning)
when verification is unavailable — ``gpg`` not installed, or the signature /
public-key assets are missing from the release. Raises RuntimeError ONLY
when verification actively FAILS (a present-but-bad signature), which is a
tamper signal we must not ignore.
Rationale for graceful degradation on "unavailable": the SHA-256 check
against ``checksums.txt`` remains in force regardless, and many install
hosts (CI, minimal containers) won't have gpg. We harden when we can andView on GitHub (pinned to c896c09c42)
Solutions
- Confirm network reachability of the URL in the message (curl -I) and fix DNS/firewall/proxy env.
- If the release tag/asset 404s, update to a Hermes version whose _IRON_PROXY_VERSION matches an existing release, or manually install the binary.
- Pre-install the binary manually (or with `hermes egress install` on a connected machine) so runtime lazy-install is never triggered.
Defensive patterns
Strategy: retry
Validate before calling
import socket, urllib.request
def release_host_reachable(url: str) -> bool:
try:
urllib.request.urlopen(urllib.request.Request(url, method="HEAD"), timeout=10)
return True
except Exception:
return False Try / catch
for attempt in range(2):
try:
find_iron_proxy(install_if_missing=True)
break
except RuntimeError as e:
if "Failed to download" in str(e) and attempt == 0:
continue # one retry for transient network
raise Prevention
- Run `hermes egress install` at provisioning time on a connected host rather than lazily at first use.
- Keep HTTP(S)_PROXY env pointing at a live proxy or unset it.
- Alert on asset-404 URLErrors — they usually mean the version pin drifted from the release catalog.
When it happens
Trigger: find_iron_proxy(install_if_missing=True) / `hermes egress install` when the machine is offline, DNS for the release host fails, a firewall blocks egress, the tagged release/asset was removed upstream, or ambient HTTP(S)_PROXY env points at a dead proxy (the download honors ambient proxy env).
Common situations: Egress-filtered containers and CI sandboxes; stale _IRON_PROXY_VERSION pin pointing at a release whose assets were re-uploaded/renamed; broken proxy env inherited from the operator's shell.
Related errors
- Could not fetch image: ${response.status}
- Unsupported platform for iron-proxy auto-install: {system} {
- Checksum mismatch for {asset_name}: expected {expected}, got
- iron-proxy checksums.txt failed GPG signature verification —
- No checksum entry for {asset_name} in {checksum_file.name}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/20de38459febe838.
Report an issue: GitHub.