langchain-ai/deepagents · error · ValueError

Path traversal not allowed

Error message

Path traversal not allowed

What it means

In virtual mode, FilesystemBackend resolves every key against its root directory and rejects paths that escape it. Any path containing a '..' segment or starting with '~' is refused up front with ValueError to keep the backend sandboxed to its root.

Source

Thrown at libs/deepagents/deepagents/backends/filesystem.py:207

        When `virtual_mode=False`, preserve legacy behavior: absolute paths are allowed
        as-is; relative paths resolve under cwd.

        Args:
            key: File path (absolute, relative, or virtual when `virtual_mode=True`).

        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:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Remove '..' segments and resolve to a path relative to the backend root before calling
  2. Expand '~' yourself and pass the resulting path rooted inside the backend directory
  3. Normalize the path (os.path.normpath / Path.resolve) and verify it stays under the intended root
  4. If you truly need access outside the root, reconfigure the backend root_dir instead of traversing

Example fix

// before
backend.read("../settings.json")
// after
backend.read("settings.json")  # relative to backend root
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import PurePosixPath
def is_safe_key(key: str) -> bool:
    p = PurePosixPath(key.lstrip("/"))
    return ".." not in p.parts and not key.startswith("~")
assert is_safe_key(user_path), "refusing traversal path"

Type guard

def safe_backend_key(key: str) -> str | None:
    parts = PurePosixPath(key.lstrip("/")).parts
    return key if ".." not in parts and not key.startswith("~") else None

Try / catch

try:
    content = backend.read(key)
except ValueError as exc:
    if "Path traversal not allowed" in str(exc):
        content = None  # or re-resolve the key against the root
    else:
        raise

Prevention

When it happens

Trigger: Calling ls, read, write, edit, delete, or grep with a key like '../secrets.txt', 'a/../../etc/passwd', or '~/config' while the backend is in virtual_mode.

Common situations: LLM-generated paths containing '..', joining user input with a relative base, or shell-style '~/file' expansion habits applied to backend keys.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


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