NousResearch/hermes-agent · error · RuntimeError

management API returned unexpected status {resp.status}

Error message

management API returned unexpected status {resp.status}

What it means

reload_proxy() expects HTTP 200 from POST /v1/reload. Non-2xx statuses surface as urllib HTTPError and are handled separately, so this branch fires only for a 2xx response that is not exactly 200 (e.g. 202 Accepted or 204 No Content) — a protocol drift between the daemon version and what this client assumes.

Source

Thrown at agent/proxy_sources/iron_proxy.py:962

            "management.token is missing — re-run `hermes egress setup`, "
            "then `hermes egress restart`."
        )

    import urllib.error
    import urllib.request

    host, port = mgmt
    req = urllib.request.Request(
        f"http://{host}:{port}/v1/reload",
        method="POST",
        headers={"Authorization": f"Bearer {token}"},
        data=b"",
    )
    try:
        with urllib.request.urlopen(req, timeout=_MGMT_RELOAD_TIMEOUT) as resp:
            if resp.status == 200:
                return True
            raise RuntimeError(
                f"management API returned unexpected status {resp.status}"
            )
    except urllib.error.HTTPError as exc:
        body = ""
        try:
            body = exc.read().decode("utf-8", errors="replace")[:500]
        except OSError:
            pass
        if exc.code == 422:
            raise RuntimeError(
                f"iron-proxy rejected the new config (validation failed; "
                f"the running ruleset is unchanged): {body}"
            ) from exc
        if exc.code == 401:
            raise RuntimeError(
                "management API rejected our key (401).  The running "
                "daemon was started with a different management.token — "
                "run `hermes egress restart`."

View on GitHub (pinned to c896c09c42)

Solutions

  1. Check whether the reload actually took effect (get_status() / hit the daemon) — a 202 usually means it did.
  2. Align versions: reinstall iron-proxy at _IRON_PROXY_VERSION (`hermes egress install` + restart) so client and daemon agree on the protocol.
  3. If the daemon legitimately returns 204 now, update the client check in reload_proxy() to accept the documented success codes.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    reload_proxy()
except RuntimeError as e:
    if "unexpected status" in str(e):
        # confirm via get_status() whether the reload took effect before retrying
        raise

Prevention

When it happens

Trigger: reload_proxy() where the management API returns 202/204 (or any 2xx != 200) — typically a newer/older iron-proxy daemon whose reload endpoint semantics changed.

Common situations: Mixing daemon and client versions: a manually installed newer iron-proxy binary behind an older Hermes, or vice versa.

Related errors


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