NousResearch/hermes-agent · error · PermissionError

Write denied: '{path}' requires interactive approval and can

Error message

Write denied: '{path}' requires interactive approval and cannot be written through the ACP file bridge.

What it means

An fs/write_text_file request from the Copilot ACP process targeted a path that passes the hard deny-list but is approval-gated (e.g. ~/.ssh/config). The ACP shim has no interactive human channel to confirm such writes, so it fails closed with this PermissionError instead of writing silently — interactive tools would prompt, but the bridge cannot.

Source

Thrown at agent/copilot_acp_client.py:742

                    "jsonrpc": "2.0",
                    "id": message_id,
                    "result": {
                        "content": content,
                    },
                }
            except Exception as exc:
                response = _jsonrpc_error(message_id, -32602, str(exc))
        elif method == "fs/write_text_file":
            try:
                path = _ensure_path_within_cwd(str(params.get("path") or ""), cwd)
                denied = get_write_denied_error(str(path))
                if denied:
                    raise PermissionError(denied)
                # Approval-gated paths (e.g. ~/.ssh/config) are not hard-denied
                # for interactive tools, but the ACP shim has no human channel
                # to confirm the write — fail closed here.
                if is_write_approval_required(str(path)):
                    raise PermissionError(
                        f"Write denied: '{path}' requires interactive approval "
                        "and cannot be written through the ACP file bridge."
                    )
                path.parent.mkdir(parents=True, exist_ok=True)
                path.write_text(str(params.get("content") or ""), encoding="utf-8")
                response = {
                    "jsonrpc": "2.0",
                    "id": message_id,
                    "result": None,
                }
            except Exception as exc:
                response = _jsonrpc_error(message_id, -32602, str(exc))
        else:
            response = _jsonrpc_error(
                message_id,
                -32601,
                f"ACP client method '{method}' is not supported by Hermes yet.",
            )

View on GitHub (pinned to c896c09c42)

Solutions

  1. Let the agent write to a neutral file, then apply the change to the gated path yourself.
  2. Make the modification manually through the interactive CLI (hermes), which can surface the approval prompt.
  3. If the path should not be gated, review the approval-required list configuration — do not bypass the guard for credential-adjacent files.

Example fix

# before — Copilot ACP tries to edit directly
write ~/.ssh/config  → PermissionError (no approval channel)
# after — agent proposes, human applies
cp config.draft ~/.ssh/config   # operator-run, reviewed
Defensive patterns

Strategy: validation

Validate before calling

# Before routing an ACP write, mirror the guard:
from agent.file_safety import is_write_approval_required, get_write_denied_error

def acp_writable(path: str) -> bool:
    return (get_write_denied_error(path) is None
            and not is_write_approval_required(path))

Try / catch

try:
    handle_fs_write(params)
except PermissionError as e:
    if 'requires interactive approval' in str(e):
        # write to a draft file instead; apply manually via interactive CLI
        ...

Prevention

When it happens

Trigger: is_write_approval_required(str(path)) returns true for the resolved write target — paths considered sensitive enough to need a human yes/no (SSH config and similar). Reached only after _ensure_path_within_cwd and get_write_denied_error both pass.

Common situations: Copilot ACP agent trying to modify SSH config or other approval-gated files inside the session workspace scope; users expecting the ACP bridge to behave like the interactive CLI's approve-on-write flow.

Related errors


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