{"record":{"id":"836996d36fa4d7ec","repo":"NousResearch/hermes-agent","slug":"pyyaml-is-required-to-write-the-iron-proxy-config","errorCode":null,"errorMessage":"PyYAML is required to write the iron-proxy config but is not installed.","messagePattern":"PyYAML is required to write the iron-proxy config but is not installed\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/proxy_sources/iron_proxy.py","lineNumber":1368,"sourceCode":"            os.close(fd)\n    except OSError as exc:\n        raise RuntimeError(\n            f\"Refusing to start: could not pre-create audit log \"\n            f\"{audit_path} with restrictive permissions ({exc}).  \"\n            f\"Move or chmod any existing file at that path and retry.\"\n        ) from exc\n\n\ndef write_proxy_config(config: Dict) -> Path:\n    \"\"\"Serialize the config dict to ``<hermes_home>/proxy/proxy.yaml``.\n\n    Uses ``yaml.safe_dump`` so we never emit Python tags.\n    \"\"\"\n\n    try:\n        import yaml  # PyYAML is already a Hermes dep\n    except ImportError as exc:\n        raise RuntimeError(\n            \"PyYAML is required to write the iron-proxy config but is not \"\n            \"installed.\"\n        ) from exc\n\n    state = _proxy_state_dir()\n    out = state / \"proxy.yaml\"\n    tmp_path = state / \".proxy.yaml.tmp\"\n    with open(tmp_path, \"w\", encoding=\"utf-8\") as f:\n        yaml.safe_dump(config, f, default_flow_style=False, sort_keys=False)\n    # Tighten perms on the temp file BEFORE the atomic replace so the\n    # final path is never briefly world-readable under a slack umask\n    # (the config embeds proxy token values).  chmod-after-replace would\n    # leave a TOCTOU window; the 0o700 state dir mitigates but same-uid\n    # processes could still race.\n    os.chmod(tmp_path, stat.S_IRUSR | stat.S_IWUSR)\n    os.replace(tmp_path, out)\n    return out\n","sourceCodeStart":1350,"sourceCodeEnd":1386,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/proxy_sources/iron_proxy.py#L1350-L1386","documentation":"write_proxy_config() serializes the config dict to proxy.yaml with yaml.safe_dump and guards the import — if PyYAML isn't importable it raises rather than writing malformed output. In a normal Hermes install PyYAML is a core dependency, so hitting this means the environment is broken or the egress module is being vendored standalone without its deps.","triggerScenarios":"write_proxy_config() (called from `hermes egress setup`) in a Python env where `import yaml` raises ImportError — stripped venvs, system-managed distro packaging that split PyYAML out, or the module copied into another project without the dependency.","commonSituations":"Running with a system python whose PyYAML package was removed by an upgrade; minimal containers where the hermes venv was recreated partially; vendoring iron_proxy.py standalone.","solutions":["Install PyYAML into the active environment: `pip install pyyaml` (or reinstall hermes-agent so its pinned deps resolve).","Verify you're running the interpreter/venv you think: `python -c \"import yaml; print(yaml.__version__)\"`.","If vendoring the module standalone, declare pyyaml in that project's dependencies."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"def pyyaml_available() -> bool:\n    try:\n        import yaml  # noqa: F401\n        return True\n    except ImportError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    write_proxy_config(cfg)\nexcept RuntimeError as e:\n    if \"PyYAML is required\" in str(e):\n        raise SystemExit(\"Install dependencies: pip install pyyaml\")","preventionTips":["Install Hermes via its supported installer/venv so PyYAML lands as a pinned dependency.","After recreating a venv, smoke-test `import yaml` before running egress setup."],"tags":["dependencies","python","config","iron-proxy"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}