langchain-ai/deepagents · error · ValueError

Path: outside root directory

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.

Solutions

  1. Inspect the resolved path printed in the message and use one contained within the root directory
  2. Remove or re-point symlinks that escape the backend root
  3. Verify the backend was constructed with the intended root_dir / cwd
  4. 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

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


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/87072a1a66a96b6b. Report an issue: GitHub.

Appendix: 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)