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

Path escapes workspace: {p}

Error message

Path escapes workspace: {p}

What it means

The workspace sandbox guard repeated at agents/s04_subagent.py:50, shared by parent and subagent in the delegation demo. Both roles' file tools route through safe_path(): join onto WORKDIR, resolve(), require the result to stay under WORKDIR. Subagents inherit the same WORKDIR, so a child asked to read a path outside the workspace gets the same rejection.

Source

Thrown at agents/s04_subagent.py:50

load_dotenv(override=True)

if os.getenv("ANTHROPIC_BASE_URL"):
    os.environ.pop("ANTHROPIC_AUTH_TOKEN", None)

WORKDIR = Path.cwd()
client = Anthropic(base_url=os.getenv("ANTHROPIC_BASE_URL"))
MODEL = os.environ["MODEL_ID"]

SYSTEM = f"You are a coding agent at {WORKDIR}. Use the task tool to delegate exploration or subtasks."
SUBAGENT_SYSTEM = f"You are a coding subagent at {WORKDIR}. Complete the given task, then summarize your findings."


# -- Tool implementations shared by parent and child --
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)"
    except (FileNotFoundError, OSError) as e:
        return f"Error: {e}"

def run_read(path: str, limit: int = None) -> str:
    try:

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Scope every delegated task (and file tool call) to workspace-relative paths
  2. If outside-workspace data is needed, use the bash tool's constrained read (e.g. `cat` with a specific file) rather than the sandboxed file tools, or copy the file into the workspace first
  3. Rewrite absolute in-workspace paths to relative before the tool call

Example fix

# before (parent -> subagent task)
"Read /tmp/errlookup-AdzUmp/docs/plan.md and summarize"
# subagent file tool: ValueError: Path escapes workspace

# after
"Read docs/plan.md and summarize"
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def is_delegation_safe_path(p: str, workdir: Path) -> 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

# parent-side: rewrite the task brief before spawning the subagent
brief = brief.replace(str(workdir) + "/", "") if is_delegation_safe_path(brief_path, workdir) else brief

Type guard

def is_relative_child_path(p: object) -> bool:
    """Subagents should only ever receive/emit relative paths."""
    return isinstance(p, str) and p != "" and not p.startswith(("/", "~")) and ".." not in Path(p).parts

Try / catch

try:
    path = safe_path(p)
except ValueError:
    return f"Sandbox rejection for {p}. Subagents must use paths relative to {WORKDIR}; ask the parent for a relative path."

Prevention

When it happens

Trigger: The parent delegates "read /var/log/system.log and summarize" and the subagent passes that absolute path to a file tool. Or a subagent follows a `../` reference from a file inside the workspace. Or the model uses an absolute path printed by a bash command's output.

Common situations: Delegation prompts that name files outside the workspace (logs, /etc configs, home-dir files). Subagents quoting absolute paths verbatim from parent instructions. Harness launched from the wrong cwd.

Related errors


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