NousResearch/hermes-agent · critical · RuntimeError

Checksum mismatch for {asset_name}: expected {expected}, got

Error message

Checksum mismatch for {asset_name}: expected {expected}, got {actual}

What it means

After downloading the iron-proxy release archive, its SHA-256 is compared against the entry in the release's checksums.txt (which is itself GPG-verified best-effort). A mismatch means the bytes on disk are not the bytes the release signed — either a corrupted/truncated download (proxies and flaky links are the usual cause) or genuine release-channel tampering. The installer refuses to extract and install the binary.

Source

Thrown at agent/proxy_sources/iron_proxy.py:505

        checksum_path = tmp / _IRON_PROXY_CHECKSUM_NAME

        logger.info("Downloading %s", asset_url)
        _http_download(asset_url, archive_path)
        _http_download(checksum_url, checksum_path)

        # Defense-in-depth (maxpetrusenko P1): verify the GPG signature of
        # checksums.txt before trusting it. The archive download honors ambient
        # proxy env (urllib), so a compromised channel could serve a matching
        # binary + checksums pair; the detached signature + pinned public key
        # close that release-channel tamper gap. Best-effort: if gpg or the
        # signature assets aren't available we log and fall back to the SHA-256
        # check alone rather than hard-failing offline installs.
        _verify_checksums_signature(tmp, checksum_path)

        expected = _expected_sha256(checksum_path, asset_name)
        actual = _sha256_file(archive_path)
        if expected.lower() != actual.lower():
            raise RuntimeError(
                f"Checksum mismatch for {asset_name}: "
                f"expected {expected}, got {actual}"
            )

        with tarfile.open(archive_path, "r:gz") as tf:
            member = _pick_tar_member(tf, _platform_binary_name())
            # PEP 706 data filter — strips ownership/mode replay (we set
            # chmod explicitly below) AND rejects symlink/hardlink members
            # that escape the extraction dir.  Required on 3.12+ to silence
            # the deprecation warning and on 3.14+ to opt into the
            # tarbomb-rejecting default.
            try:
                tf.extract(member, tmp, filter="data")  # noqa: S202
            except TypeError:
                # Python < 3.12 — filter kw didn't exist yet; the
                # _pick_tar_member sanitization already rejects path
                # traversal so this is acceptable.
                tf.extract(member, tmp)  # noqa: S202

View on GitHub (pinned to c896c09c42)

Solutions

  1. Delete any partial download/temp state under the proxy state dir and retry `hermes egress install` on a stable connection.
  2. Check for intercepting proxies: verify `curl -L <asset-url> | sha256sum` matches the published checksums.txt entry from the same release page.
  3. If the mismatch reproduces on a clean network, treat it as a possible release-channel compromise — do NOT bypass the check; verify the checksums.txt GPG signature manually against the project's pinned key and report it.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    find_iron_proxy(install_if_missing=True)
except RuntimeError as e:
    if "Checksum mismatch" in str(e):
        # do NOT auto-retry in a loop: clear partial downloads once, retry once,
        # then surface to a human — this can indicate tampering
        raise

Prevention

When it happens

Trigger: find_iron_proxy(install_if_missing=True) / `hermes egress install` completes the archive download, but _sha256_file(archive_path) != _expected_sha256(checksum_path, asset_name). Typical causes: a corporate MITM proxy rewriting the GitHub asset download, a partially-written file from a dropped connection, or a partially-written file left in the temp dir.

Common situations: Installing behind an intercepting corporate proxy or on flaky Wi-Fi; a cached/partial download being reused; a genuinely compromised mirror (rare, but this check plus the GPG layer exists precisely for that).

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/99f794da59ef3ddc. Report an issue: GitHub.