shareAI-lab/learn-claude-code · error · ValueError
Mailbox path escapes directory: {agent!r}
Error message
Mailbox path escapes directory: {agent!r} What it means
The second guard in MessageBus._path(): even with a lexically valid name, if MAILBOX_DIR/<agent>.jsonl resolves outside MAILBOX_ROOT the path is refused. This catches symlinked mailbox files or a relocated/symlinked MAILBOX_DIR that would let messages escape the mailbox store — a path-traversal defense in depth after the regex check.
Source
Thrown at s15_integrated_harness/code.py:1027
VALID_AGENT_NAME = re.compile(r"^[A-Za-z0-9_-]{1,64}$")
RESERVED_TEAMMATE_NAMES = {"lead", "agent"}
def is_valid_agent_name(name: str) -> bool:
return bool(VALID_AGENT_NAME.fullmatch(name))
class MessageBus:
def __init__(self):
self._lock = threading.RLock()
self._changed = threading.Condition(self._lock)
def _path(self, agent: str) -> Path:
if not is_valid_agent_name(agent):
raise ValueError(f"Invalid mailbox recipient: {agent!r}")
path = (MAILBOX_DIR / f"{agent}.jsonl").resolve()
if not path.is_relative_to(MAILBOX_ROOT):
raise ValueError(f"Mailbox path escapes directory: {agent!r}")
return path
def _read_unlocked(self, agent: str) -> list[dict]:
inbox = self._path(agent)
if not inbox.exists():
return []
msgs = [json.loads(line) for line in inbox.read_text().splitlines()
if line.strip()]
inbox.unlink()
return msgs
def send(self, from_agent: str, to_agent: str, content: str,
msg_type: str = "message", metadata: dict | None = None):
msg = {"from": from_agent, "to": to_agent,
"content": content, "type": msg_type,
"ts": time.time(), "metadata": metadata or {}}
with self._changed:
MAILBOX_DIR.mkdir(parents=True, exist_ok=True)View on GitHub (pinned to 985456f4ad)
Solutions
- Remove symlinks from the mailbox directory; mailboxes are plain .jsonl files managed by MessageBus.
- Keep MAILBOX_DIR/MAILBOX_ROOT as real directories inside the workspace.
- Audit with `find <mailbox_dir> -type l` and delete offenders.
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def mailbox_store_ok(mailbox_dir: Path, mailbox_root: Path) -> bool:
resolved = mailbox_dir.resolve()
return resolved.is_relative_to(mailbox_root.resolve()) and not any(
p.is_symlink() for p in resolved.glob("*") if p.is_file() or p.is_symlink()
) Try / catch
try:
bus.send(a, b, msg)
except ValueError as e:
if "escapes directory" in str(e):
raise SystemExit("mailbox directory misconfigured (symlink/escape)")
raise Prevention
- Never place symlinks in the mailbox directory.
- Keep MAILBOX_DIR a real directory under the workspace.
- Audit with `find <mailbox_dir> -type l` after setup changes.
When it happens
Trigger: A pre-created <agent>.jsonl symlink inside MAILBOX_DIR pointing elsewhere; MAILBOX_DIR itself a symlink outside the workspace root; MAILBOX_ROOT not under WORKDIR after config changes.
Common situations: Users symlinking a mailbox into a shared dir; packaging the harness with the mailbox dir on an external mount; leftover symlinks from debugging.
Related errors
- Memory path escapes the store: {filename}
- Worktree path escapes directory: {name!r}
- Mailbox path escapes directory: {agent!r}
- Tasks directory escapes workspace
- Path escapes workspace: {p}
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/6ff2be6e3bb59a27.
Report an issue: GitHub.