NousResearch/hermes-agent · error · RuntimeError

iron-proxy exited immediately (code {proc.returncode}). Last

Error message

iron-proxy exited immediately (code {proc.returncode}). Last log lines:
{tail}

What it means

During the startup grace poll loop, proc.poll() returned non-None before the tunnel port ever listened — the iron-proxy process died immediately. The pidfile (written right after Popen) is unlinked and the last 20 log lines are attached so the config/runtime failure is visible. This is the 'died early' branch inside the do-while listening check.

Source

Thrown at agent/proxy_sources/iron_proxy.py:1954

    install_handlers = (
        platform.system() != "Windows"
        and threading.current_thread() is threading.main_thread()
    )
    if install_handlers:
        prev_sigint = signal.signal(signal.SIGINT, _interrupt_handler)
        prev_sigterm = signal.signal(signal.SIGTERM, _interrupt_handler)
    try:
        deadline = time.time() + _STARTUP_GRACE_SECONDS
        # Do-while shape: check listening at least once even when the
        # grace window is 0 (test harness / synchronous fast-path).
        while True:
            if proc.poll() is not None:
                tail = _tail_log(log_path, lines=20)
                try:
                    pidfile.unlink()
                except FileNotFoundError:
                    pass
                raise RuntimeError(
                    f"iron-proxy exited immediately (code {proc.returncode}). "
                    f"Last log lines:\n{tail}"
                )
            if _port_listening(probe_host, tunnel_port):
                listening = True
                break
            if time.time() >= deadline:
                break
            time.sleep(0.1)
    finally:
        if install_handlers:
            signal.signal(signal.SIGINT, prev_sigint)
            signal.signal(signal.SIGTERM, prev_sigterm)

    # Final exit check — process may have died right at deadline.
    if proc.poll() is not None:
        tail = _tail_log(log_path, lines=20)
        try:

View on GitHub (pinned to c896c09c42)

Solutions

  1. Read the 'Last log lines' in the message — the proxy's own error is almost always the first line there
  2. Fix the reported config problem in the generated config / config.yaml and retry `hermes egress start`
  3. If the log shows 'address already in use', free the port or change tunnel_port, then retry
  4. If the schema changed after an upgrade, re-run `hermes egress setup` to regenerate the config

Example fix

# before: config references a missing cert
# RuntimeError: iron-proxy exited immediately (code 1). Last log lines:
#   error: cannot open cert file /etc/ssl/wrong.pem
# fix path in config, then:
hermes egress start

# after: proxy stays alive through the grace window and binds the port
Defensive patterns

Strategy: try-catch

Validate before calling

import yaml
from pathlib import Path

def config_parses(cfg: Path) -> bool:
    try:
        yaml.safe_load(cfg.read_text())
        return True
    except yaml.YAMLError:
        return False

# and pre-check the port is free:
import socket

def port_free(host: str, port: int) -> bool:
    with socket.socket() as s:
        return s.connect_ex((host, port)) != 0

Try / catch

try:
    start_proxy(...)
except RuntimeError as e:
    if 'exited immediately' in str(e):
        tail = str(e).split('Last log lines:', 1)[-1]
        diagnose_and_fix(tail)  # fix config/port/cert, then retry once

Prevention

When it happens

Trigger: start_proxy() where the proxy binary rejects its config (bad YAML, unknown fields), cannot bind its port, cannot read a referenced cert/key file, or crashes on startup — all within _STARTUP_GRACE_SECONDS.

Common situations: Hand-edited config.yaml with a syntax or schema error; port already in use by another service; TLS key/cert paths wrong; a proxy version whose config schema changed after an upgrade; missing capabilities for binding a low port.

Related errors


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