shareAI-lab/learn-claude-code · error · ValueError

Path escapes workspace: {p}

Error message

Path escapes workspace: {p}

What it means

The workspace sandbox guard at agents/s09_agent_teams.py:259 (_safe_path, underscore-prefixed because this script layers team tools on the s02 base). Same semantics: join onto WORKDIR, resolve(), require the result under WORKDIR. It governs the shared base file tools used by team members.

Source

Thrown at agents/s09_agent_teams.py:259

        if not self.config["members"]:
            return "No teammates."
        lines = [f"Team: {self.config['team_name']}"]
        for m in self.config["members"]:
            lines.append(f"  {m['name']} ({m['role']}): {m['status']}")
        return "\n".join(lines)

    def member_names(self) -> list:
        return [m["name"] for m in self.config["members"]]


TEAM = TeammateManager(TEAM_DIR)


# -- Base tool implementations (these base tools are unchanged from s02) --
def _safe_path(p: str) -> Path:
    path = (WORKDIR / p).resolve()
    if not path.is_relative_to(WORKDIR):
        raise ValueError(f"Path escapes workspace: {p}")
    return path


def _run_bash(command: str) -> str:
    dangerous = ["rm -rf /", "sudo", "shutdown", "reboot", "> /dev/"]
    if any(d in command for d in dangerous):
        return "Error: Dangerous command blocked"
    try:
        r = subprocess.run(
            command, shell=True, cwd=WORKDIR,
            capture_output=True, text=True, timeout=120,
        )
        out = (r.stdout + r.stderr).strip()
        return out[:50000] if out else "(no output)"
    except subprocess.TimeoutExpired:
        return "Error: Timeout (120s)"

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Normalize paths to workspace-relative before file tool calls, especially paths received from other teammates
  2. Keep team config and message conventions on relative paths
  3. Launch the harness from the workspace root

Example fix

# before (teammate message: "check /tmp/errlookup-AdzUmp/src/api.py")
_safe_path("/tmp/errlookup-AdzUmp/src/api.py")
# ValueError: Path escapes workspace

# after
import os
_safe_path(os.path.relpath("/tmp/errlookup-AdzUmp/src/api.py", WORKDIR))  # "src/api.py"
Defensive patterns

Strategy: validation

Validate before calling

import os
from pathlib import Path

def normalize_received_path(p: str, workdir: Path) -> str | None:
    """Teammates send paths in any form; make them workspace-relative or drop them."""
    try:
        cand = Path(p)
        abs_c = cand if cand.is_absolute() else (workdir / cand)
        abs_c = abs_c.resolve()
        return os.path.relpath(abs_c, workdir) if abs_c.is_relative_to(workdir) else None
    except (OSError, ValueError, RuntimeError):
        return None

rel = normalize_received_path(teammate_path, WORKDIR)
assert rel, f"teammate path {teammate_path} escapes workspace"

Type guard

def is_team_safe_path(p: object, workdir) -> bool:
    if not isinstance(p, str) or not p:
        return False
    try:
        return (workdir / p).resolve().is_relative_to(workdir)
    except (OSError, RuntimeError):
        return False

Try / catch

try:
    path = _safe_path(p)
except ValueError:
    return f"Teammate path {p} rejected by sandbox. Re-issue as a workspace-relative path."

Prevention

When it happens

Trigger: A teammate agent passes an absolute path or `../` traversal to a file tool — often a path quoted verbatim from a teammate message or from the team config (TEAM_DIR files may embed absolute paths). Symlink escapes and cwd mismatch also trigger it.

Common situations: Team protocols where one member posts an absolute path and another copies it into a tool call. Harness started outside the workspace. Teammate config files referencing machine-specific paths.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/9347abe68665c2c8. Report an issue: GitHub.