NousResearch/hermes-agent · error · RuntimeError
iron-proxy rejected the new config (validation failed; the r
Error message
iron-proxy rejected the new config (validation failed; the running ruleset is unchanged): {body} What it means
The management API validates the submitted config atomically before swapping the transform pipeline; invalid config gets HTTP 422 and the daemon keeps running the old ruleset unchanged. The RuntimeError embeds up to 500 bytes of the response body, which contains the validation error details. This is safe-by-design: a rejected reload never leaves the proxy half-configured.
Source
Thrown at agent/proxy_sources/iron_proxy.py:972
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`."
) from exc
raise RuntimeError(
f"management reload failed (HTTP {exc.code}): {body}"
) from exc
except (urllib.error.URLError, OSError) as exc:
# A daemon started from a pre-management config is alive but has
# no listener on the management port.
raise RuntimeError(
f"could not reach the management API at {host}:{port} ({exc}). "
"If the daemon was started before reload support, run "View on GitHub (pinned to c896c09c42)
Solutions
- Read the validation detail in the error body — it names the offending field/rule.
- Fix that field in the config source and re-run `hermes egress reload`; the running proxy was unaffected, so there is no urgency beyond the rules you wanted being inactive.
- Prefer generating config through `hermes egress setup`-driven paths rather than free-handing YAML when possible.
Defensive patterns
Strategy: try-catch
Try / catch
try:
reload_proxy()
except RuntimeError as e:
if "rejected the new config" in str(e):
# parse validation detail from message body, fix config, re-run
# running ruleset is unchanged — safe to retry after fix
raise Prevention
- Validate generated rule config with the daemon's schema (or the setup command) before every reload.
- Treat 422 bodies as authoritative field-level errors; fix the named field rather than rewriting the whole config.
When it happens
Trigger: reload_proxy() / `hermes egress reload` after editing proxy rules into an invalid state — bad YAML structure in a rule, unknown transform name, malformed allowlist entry, or a schema field the daemon version doesn't understand.
Common situations: Hand-editing the egress rules in config/proxy.yaml and reloading; scripted config generation that emits a subtly wrong field; schema drift between the daemon version and the docs used while editing.
Related errors
- The generated proxy.yaml has no management listener (written
- management.token is missing — re-run `hermes egress setup`,
- management API rejected our key (401). The running daemon w
- Invalid profile name: ${value}
- SSH host is required.
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/3ea70361d5714ec8.
Report an issue: GitHub.