langchain-ai/deepagents · error · ValueError
Path:{full} outside root directory: {self.cwd}
Error message
Path:{full} outside root directory: {self.cwd} What it means
After resolving a virtual-mode path, the backend verifies the fully resolved (symlink-followed) path sits under the backend root via relative_to. If the resolved path escapes the root — even when the textual path looked safe — ValueError is raised. This catches symlinks that point outside the sandbox.
Source
Thrown at libs/deepagents/deepagents/backends/filesystem.py:213
Returns:
Resolved absolute `Path` object.
Raises:
ValueError: If path traversal is attempted in `virtual_mode` or if the
resolved path escapes the root directory.
OSError: If the path is a symlink loop (`ELOOP`).
"""
if self.virtual_mode:
vpath = key if key.startswith("/") else "/" + key
if ".." in vpath or vpath.startswith("~"):
msg = "Path traversal not allowed"
raise ValueError(msg)
full = (self.cwd / vpath.lstrip("/")).resolve()
try:
full.relative_to(self.cwd)
except ValueError:
msg = f"Path:{full} outside root directory: {self.cwd}"
raise ValueError(msg) from None
_raise_if_symlink_loop(full)
return full
path = Path(key)
if path.is_absolute():
_raise_if_symlink_loop(path)
return path
resolved = (self.cwd / path).resolve()
_raise_if_symlink_loop(resolved)
return resolved
def _to_virtual_path(self, path: Path) -> str:
"""Convert a filesystem path to a virtual path relative to cwd.
Args:
path: Filesystem path to convert.
Returns:View on GitHub (pinned to a1af029e6e)
Solutions
- Inspect the resolved path printed in the message and use one contained within the root directory
- Remove or re-point symlinks that escape the backend root
- Verify the backend was constructed with the intended root_dir / cwd
- Copy external files into the root rather than linking to them
Example fix
// before
backend.read("shared-link/data.txt") # symlink -> /etc/data.txt
// after
cp /etc/data.txt ./data.txt
backend.read("data.txt") Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def stays_in_root(root: Path, key: str) -> bool:
resolved = (root / key.lstrip("/")).resolve()
return resolved == root or root in resolved.parents Try / catch
try:
data = backend.read(key)
except ValueError as exc:
if str(exc).startswith("Path:") and "outside root directory" in str(exc):
data = None # symlink or path escapes sandbox; handle explicitly
else:
raise Prevention
- Audit symlinks inside the workspace for external targets
- Copy external files into the backend root instead of linking
- Confirm root_dir matches your intended sandbox when constructing the backend
When it happens
Trigger: Calling ls/read/write/edit/delete/grep with a path (or a symlink target) that resolves outside self.cwd, e.g. 'link' pointing to /etc, or a deeply nested '../../' chain that survives normalization.
Common situations: Symlinks created inside the workspace that point to external files, or mounting a workspace where cwd differs from expectations (running from a different working directory).
Related errors
- Path traversal not allowed
- debug log directory is not a real directory: {path}
- enable_interpreter=True is not supported with a remote sandb
- Failed while waiting for Vercel sandbox startup.
- Missing dependencies for '{provider}' sandbox. {install_hint
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/87072a1a66a96b6b.
Report an issue: GitHub.