{"record":{"id":"5427be6ce8b02d88","repo":"NousResearch/hermes-agent","slug":"management-api-returned-unexpected-status-resp-st","errorCode":null,"errorMessage":"management API returned unexpected status {resp.status}","messagePattern":"management API returned unexpected status (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/proxy_sources/iron_proxy.py","lineNumber":962,"sourceCode":"            \"management.token is missing — re-run `hermes egress setup`, \"\n            \"then `hermes egress restart`.\"\n        )\n\n    import urllib.error\n    import urllib.request\n\n    host, port = mgmt\n    req = urllib.request.Request(\n        f\"http://{host}:{port}/v1/reload\",\n        method=\"POST\",\n        headers={\"Authorization\": f\"Bearer {token}\"},\n        data=b\"\",\n    )\n    try:\n        with urllib.request.urlopen(req, timeout=_MGMT_RELOAD_TIMEOUT) as resp:\n            if resp.status == 200:\n                return True\n            raise RuntimeError(\n                f\"management API returned unexpected status {resp.status}\"\n            )\n    except urllib.error.HTTPError as exc:\n        body = \"\"\n        try:\n            body = exc.read().decode(\"utf-8\", errors=\"replace\")[:500]\n        except OSError:\n            pass\n        if exc.code == 422:\n            raise RuntimeError(\n                f\"iron-proxy rejected the new config (validation failed; \"\n                f\"the running ruleset is unchanged): {body}\"\n            ) from exc\n        if exc.code == 401:\n            raise RuntimeError(\n                \"management API rejected our key (401).  The running \"\n                \"daemon was started with a different management.token — \"\n                \"run `hermes egress restart`.\"","sourceCodeStart":944,"sourceCodeEnd":980,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/proxy_sources/iron_proxy.py#L944-L980","documentation":"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.","triggerScenarios":"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.","commonSituations":"Mixing daemon and client versions: a manually installed newer iron-proxy binary behind an older Hermes, or vice versa.","solutions":["Check whether the reload actually took effect (get_status() / hit the daemon) — a 202 usually means it did.","Align versions: reinstall iron-proxy at _IRON_PROXY_VERSION (`hermes egress install` + restart) so client and daemon agree on the protocol.","If the daemon legitimately returns 204 now, update the client check in reload_proxy() to accept the documented success codes."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    reload_proxy()\nexcept RuntimeError as e:\n    if \"unexpected status\" in str(e):\n        # confirm via get_status() whether the reload took effect before retrying\n        raise","preventionTips":["Keep the iron-proxy binary version pinned via `hermes egress install` so client and daemon protocol agree.","Verify rule changes took effect (status/audit log) rather than assuming success from the call returning."],"tags":["api","daemon","version-skew","iron-proxy"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}