{"repo":"NousResearch/hermes-agent","public_id":"2878","display_label":"Docker container env vars silently ignored in config","summary":"Multiple reports and proposed fixes around docker_forward_env and docker_env config keys being dropped or never forwarded when creating Docker sandbox containers. The members describe the same bug from several angles along with various fix attempts.","subsystem":"environments","counts":{"members":15,"open_issues":0,"open_issues_distinct":0,"open_prs":1,"closed_issues":5,"merged_prs":2,"attempt_prs":8},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":22852,"merged_at":"2026-05-10T00:53:35+00:00"},"resolution":{"state":"partially_resolved","by":"pr-22852"},"freshness":{"state":"verified","last_verified_at":"2026-05-10T00:53:35+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.11238095238095239},"fix_edges":[{"issue_number":20537,"pr_number":22852,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-05-10T00:53:35+00:00"}],"members":[{"kind":"issue","number":2878,"title":"fix(docker): docker_forward_env config key silently ignored — missing from container_config dict","url":null,"state":"closed"},{"kind":"issue","number":4916,"title":"[Bug]: terminal_tool drops docker_forward_env when creating container sandboxes","url":null,"state":"closed"},{"kind":"issue","number":5722,"title":"terminal.docker_forward_env and terminal.docker_env are silently ignored from config.yaml","url":null,"state":"closed"},{"kind":"issue","number":12534,"title":"Docker sandbox never receives env vars from docker_forward_env: missing keys in container_config","url":null,"state":"closed"},{"kind":"issue","number":20537,"title":"Bug: docker_env configuration is completely ignored (env_mappings missing docker_env)","url":null,"state":"closed"},{"kind":"pr","number":2879,"title":"fix(docker): include docker_forward_env in container_config dict","url":null,"state":"closed","close_reason":{"category":"stale_abandoned","implication":"active"},"merged":false},{"kind":"pr","number":2881,"title":"fix(docker): include docker_forward_env in container_config dict","url":null,"state":"closed","close_reason":{"category":"implemented_elsewhere","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":4917,"title":"fix(terminal): pass docker_forward_env through terminal tool","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"db86ed199082d168546179d1c9200467039927bb","number":0},{"kind":"pr","value":"#4916","number":4916}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":4972,"title":"fix: include docker_forward_env in terminal_tool container_config","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"db86ed199082d168546179d1c9200467039927bb","number":0},{"kind":"pr","value":"#4916","number":4916}],"category":"merged_via","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":12825,"title":"fix(docker): forward configured environment variables to sandbox containers","url":null,"state":"open","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":14235,"title":"fix(terminal): forward docker_forward_env and docker_env to container_config (salvage #10162)","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":17620,"title":"fix(execute_code): forward docker_forward_env into container_config","url":null,"state":"closed","close_reason":{"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":20549,"title":"fix(docker): bridge terminal docker_env config","url":null,"state":"closed","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":22626,"title":"fix(terminal): bridge docker_env config to TERMINAL_DOCKER_ENV","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#22852","number":22852}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":22852,"title":"fix(terminal): bridge docker_env config to TERMINAL_DOCKER_ENV (salvage #22626)","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["cli.py","gateway/run.py","hermes_cli/config.py","tests/tools/test_terminal_config_env_sync.py","tools/terminal_tool.py"],"fix_hunks":[{"file":"cli.py","hunks":["@@ -517,6 +517,7 @@ def load_cli_config() -> Dict[str, Any]:\n         \"container_disk\": \"TERMINAL_CONTAINER_DISK\",\n         \"container_persistent\": \"TERMINAL_CONTAINER_PERSISTENT\",\n         \"docker_volumes\": \"TERMINAL_DOCKER_VOLUMES\",\n+        \"docker_env\": \"TERMINAL_DOCKER_ENV\",\n         \"docker_mount_cwd_to_workspace\": \"TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE\",\n         \"docker_run_as_host_user\": \"TERMINAL_DOCKER_RUN_AS_HOST_USER\",\n         \"sandbox_dir\": \"TERMINAL_SANDBOX_DIR\",","@@ -540,7 +541,7 @@ def load_cli_config() -> Dict[str, Any]:\n                 continue\n             if _file_has_terminal_config or env_var not in os.environ:\n                 val = terminal_config[config_key]\n-                if isinstance(val, list):\n+                if isinstance(val, (list, dict)):\n                     os.environ[env_var] = json.dumps(val)\n                 else:\n                     os.environ[env_var] = str(val)"]},{"file":"gateway/run.py","hunks":["@@ -460,6 +460,7 @@ def _reload_runtime_env_preserving_config_authority() -> None:\n                 \"container_disk\": \"TERMINAL_CONTAINER_DISK\",\n                 \"container_persistent\": \"TERMINAL_CONTAINER_PERSISTENT\",\n                 \"docker_volumes\": \"TERMINAL_DOCKER_VOLUMES\",\n+                \"docker_env\": \"TERMINAL_DOCKER_ENV\",\n                 \"docker_mount_cwd_to_workspace\": \"TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE\",\n                 \"docker_run_as_host_user\": \"TERMINAL_DOCKER_RUN_AS_HOST_USER\",\n                 \"sandbox_dir\": \"TERMINAL_SANDBOX_DIR\",","@@ -478,7 +479,7 @@ def _reload_runtime_env_preserving_config_authority() -> None:\n                     # receives a literal \"~/\" which the kernel rejects.\n                     if _cfg_key == \"cwd\" and isinstance(_val, str):\n                         _val = os.path.expanduser(_val)\n-                    if isinstance(_val, list):\n+                    if isinstance(_val, (list, dict)):\n                         os.environ[_env_var] = json.dumps(_val)\n                     else:\n                         os.environ[_env_var] = str(_val)"]},{"file":"hermes_cli/config.py","hunks":["@@ -4843,6 +4843,7 @@ def set_config_value(key: str, value: str):\n         \"terminal.vercel_runtime\": \"TERMINAL_VERCEL_RUNTIME\",\n         \"terminal.docker_mount_cwd_to_workspace\": \"TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE\",\n         \"terminal.docker_run_as_host_user\": \"TERMINAL_DOCKER_RUN_AS_HOST_USER\",\n+        \"terminal.docker_env\": \"TERMINAL_DOCKER_ENV\",\n         # terminal.cwd intentionally excluded — CLI resolves at runtime,\n         # gateway bridges it in gateway/run.py. Persisting to .env causes\n         # stale values to poison child processes."]},{"file":"tests/tools/test_terminal_config_env_sync.py","hunks":["@@ -208,3 +208,19 @@ def test_docker_mount_cwd_to_workspace_is_bridged_everywhere():\n     assert \"docker_mount_cwd_to_workspace\" in _gateway_env_map_keys()\n     assert \"docker_mount_cwd_to_workspace\" in _save_config_env_sync_keys()\n     assert \"TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE\" in _terminal_tool_env_var_names()\n+\n+\n+def test_docker_env_is_bridged_everywhere():\n+    \"\"\"Regression pin for docker_env config key being silently ignored.\n+\n+    ``terminal.docker_env`` in config.yaml specifies extra env vars to inject\n+    into the Docker container at runtime.  The key was present in\n+    _create_environment's container_config consumer (line ~1130) but never\n+    bridged from config.yaml to TERMINAL_DOCKER_ENV, so the dict was always\n+    empty regardless of what the user set.  Guard all four bridging points so\n+    this cannot regress.\n+    \"\"\"\n+    assert \"docker_env\" in _cli_env_map_keys()\n+    assert \"docker_env\" in _gateway_env_map_keys()\n+    assert \"docker_env\" in _save_config_env_sync_keys()\n+    assert \"TERMINAL_DOCKER_ENV\" in _terminal_tool_env_var_names()"]},{"file":"tools/terminal_tool.py","hunks":["@@ -1085,6 +1085,7 @@ def _get_env_config() -> Dict[str, Any]:\n         \"container_disk\": _parse_env_var(\"TERMINAL_CONTAINER_DISK\", \"51200\"),        # MB (default 50GB)\n         \"container_persistent\": os.getenv(\"TERMINAL_CONTAINER_PERSISTENT\", \"true\").lower() in (\"true\", \"1\", \"yes\"),\n         \"docker_volumes\": _parse_env_var(\"TERMINAL_DOCKER_VOLUMES\", \"[]\", json.loads, \"valid JSON\"),\n+        \"docker_env\": _parse_env_var(\"TERMINAL_DOCKER_ENV\", \"{}\", json.loads, \"valid JSON\"),\n         \"docker_run_as_host_user\": os.getenv(\"TERMINAL_DOCKER_RUN_AS_HOST_USER\", \"false\").lower() in (\"true\", \"1\", \"yes\"),\n     }\n \n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}