NousResearch/hermes-agent · error · PermissionError

Path '{resolved}' is outside the session cwd '{root}'.

Error message

Path '{resolved}' is outside the session cwd '{root}'.

What it means

An ACP file-system request resolved to a path outside the session's cwd. After requiring an absolute path, _ensure_path_within_cwd resolves symlinks and requires the result to be relative_to(Path(cwd).resolve()); a ValueError from relative_to becomes this PermissionError. It confines the Copilot ACP process to the session workspace.

Source

Thrown at agent/copilot_acp_client.py:379

        cursor = max(cursor, end)
    if cursor < len(text):
        parts.append(text[cursor:])

    cleaned = "\n".join(p.strip() for p in parts if p and p.strip()).strip()
    return extracted, cleaned



def _ensure_path_within_cwd(path_text: str, cwd: str) -> Path:
    candidate = Path(path_text)
    if not candidate.is_absolute():
        raise PermissionError("ACP file-system paths must be absolute.")
    resolved = candidate.resolve()
    root = Path(cwd).resolve()
    try:
        resolved.relative_to(root)
    except ValueError as exc:
        raise PermissionError(f"Path '{resolved}' is outside the session cwd '{root}'.") from exc
    return resolved


class _ACPChatCompletions:
    def __init__(self, client: "CopilotACPClient"):
        self._client = client

    def create(self, **kwargs: Any) -> Any:
        return self._client._create_chat_completion(**kwargs)


class _ACPChatNamespace:
    def __init__(self, client: "CopilotACPClient"):
        self.completions = _ACPChatCompletions(client)


class CopilotACPClient:
    """Minimal OpenAI-client-compatible facade for Copilot ACP."""

View on GitHub (pinned to c896c09c42)

Solutions

  1. Run the session from a directory that contains everything the agent needs, so cwd covers the accessed paths.
  2. Check for symlinks in the failing path (ls -l) and replace/relocate ones that escape the workspace.
  3. If a legitimate need exists to work on multiple roots, start Hermes in a parent directory containing them.

Example fix

# before — session started in subdir, Copilot reaches for sibling
hermes  # cwd=/repo/packages/app  → path /repo/packages/lib/x.ts denied
# after — start at the repo root so cwd contains both
hermes  # cwd=/repo
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def within_cwd(path_text: str, cwd: str) -> bool:
    resolved = Path(path_text).resolve()
    try:
        resolved.relative_to(Path(cwd).resolve())
        return True
    except ValueError:
        return False

Try / catch

try:
    handle_fs_request(params)
except PermissionError as e:
    if "outside the session cwd" in str(e):
        # relocate the work under cwd or restart session in a wider root
        ...

Prevention

When it happens

Trigger: An fs/read_text_file or fs/write_text_file from the Copilot ACP process targeting an absolute path outside the session cwd, or a path inside the cwd that is a symlink resolving outside it (candidate.resolve() follows links).

Common situations: Copilot CLI trying to read config or caches from $HOME while the session cwd is a project directory; symlinked dependencies (monorepo layouts) escaping the workspace; probing behavior from a misbehaving ACP peer.

Related errors


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