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/s05_skill_loading.py:121 in the skill-loading agent. All file tool calls pass through safe_path(), which resolves the model's path against WORKDIR and rejects anything that escapes it. This variant coexists with load_skill, so failures usually involve paths the model picked up from skill bodies rather than the skill mechanism itself.
Source
Thrown at agents/s05_skill_loading.py:121
return f"Error: Unknown skill '{name}'. Available: {', '.join(self.skills.keys())}"
return f"<skill name=\"{name}\">\n{skill['body']}\n</skill>"
SKILL_LOADER = SkillLoader(SKILLS_DIR)
# Layer 1: skill metadata injected into system prompt
SYSTEM = f"""You are a coding agent at {WORKDIR}.
Use load_skill to access specialized knowledge before tackling unfamiliar topics.
Skills available:
{SKILL_LOADER.get_descriptions()}"""
# -- Tool implementations --
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)"
def run_read(path: str, limit: int = None) -> str:
try:
lines = safe_path(path).read_text().splitlines()
if limit and limit < len(lines):View on GitHub (pinned to 985456f4ad)
Solutions
- Keep paths in file tool calls relative to WORKDIR; treat skill-internal paths as data to rewrite, not to follow blindly
- Author skills with workspace-relative paths or placeholders
- Use load_skill (not raw file reads) to access skill content; if skill files are outside WORKDIR, that is by design
Example fix
# before
read_file("/home/beagle/.agents/skills/agnt/SKILL.md")
# ValueError: Path escapes workspace
# after
load_skill("agnt") # content is returned by the skill loader Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def is_skill_safe_path(p: str, workdir: Path) -> bool:
try:
return (workdir / p).resolve().is_relative_to(workdir)
except (OSError, RuntimeError):
return False
if not is_skill_safe_path(p, WORKDIR):
p = None # do not call the file tool; use load_skill content instead Type guard
def is_workspace_path_str(p: object) -> bool:
return isinstance(p, str) and bool(p) and not p.startswith(("/", "~")) and ".." not in Path(p).parts Try / catch
try:
path = safe_path(p)
except ValueError:
return f"{p} is outside the workspace. Use load_skill for skill content and relative paths for files." Prevention
- Access skill content via load_skill, never raw file reads of the skills dir
- Treat absolute paths found inside skill bodies as data to rewrite, not paths to follow
- Author skills with workspace-relative paths or explicit placeholders
When it happens
Trigger: A loaded skill's instructions reference files by absolute path or `../` and the model copies them into a file tool call. Or the model tries to read the skill files themselves from outside the workspace (SKILL_LOADER may live elsewhere). Absolute paths and symlink escapes resolve outside WORKDIR and are rejected.
Common situations: Skill markdown containing machine-specific absolute paths from the skill author's machine. Model attempting to inspect the skills directory directly instead of via load_skill. Harness cwd mismatch.
Related errors
- Path escapes workspace: {p}
- Path escapes workspace: {p}
- Path escapes workspace: {p}
- Path escapes workspace: {p}
- Path escapes workspace: {p}
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/ce0c3e853a939fb5.
Report an issue: GitHub.