langchain-ai/deepagents · error · NotImplementedError

Permission path must not contain '~': {path!r}

Error message

Permission path must not contain '~': {path!r}

What it means

FilesystemPermission patterns must not contain a '~' component; home-directory shorthand is not supported by the permission matcher, so it raises NotImplementedError rather than silently mis-matching. Use explicit absolute paths instead.

Source

Thrown at libs/deepagents/deepagents/middleware/filesystem.py:420

        (`ls`/`glob`/`grep`) fire the interrupt based on whether their
        search subtree could overlap the rule's anchored prefix, so a fully
        unanchored pattern (`/**/secrets`) collapses to `/` and
        conservatively over-fires for any bulk call.
    """

    def __post_init__(self) -> None:
        """Validate permission path patterns."""
        for path in self.paths:
            if not path.startswith("/"):
                msg = f"Permission path must start with '/': {path!r}"
                raise ValueError(msg)
            parts = PurePosixPath(path.replace("\\", "/")).parts
            if ".." in parts:
                msg = f"Permission path must not contain '..': {path!r}"
                raise ValueError(msg)
            if "~" in parts:
                msg = f"Permission path must not contain '~': {path!r}"
                raise NotImplementedError(msg)


def _check_fs_permission(
    rules: list[FilesystemPermission],
    operation: FilesystemOperation,
    path: str,
) -> Literal["allow", "deny", "interrupt"]:
    for rule in rules:
        if operation not in rule.operations:
            continue
        if any(wcglob.globmatch(path, pattern, flags=_FS_WCMATCH_FLAGS) for pattern in rule.paths):
            return rule.mode
    return "allow"


def _wildcard_delete_overlap(pattern: str, anchor: str, target: str) -> bool:
    """Check whether a wildcard deny pattern overlaps a recursive delete target.

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Call os.path.expanduser on the pattern before constructing the permission, then verify it still starts with '/'
  2. Replace '~' with the concrete absolute home path
  3. Drop '~' from config templates and document absolute paths only

Example fix

// before
FilesystemPermission(paths=["~/.ssh/**"])
// after
FilesystemPermission(paths=[os.path.expanduser("~/.ssh/**")])
Defensive patterns

Strategy: validation

Validate before calling

import os
def expand_tilde(p: str) -> str:
    expanded = os.path.expanduser(p)
    if "~" in expanded.split("/"):
        raise ValueError(f"unexpandable '~' in permission path: {p!r}")
    return expanded

Try / catch

try:
    perm = FilesystemPermission(paths=[os.path.expanduser(p) for p in paths])
except (ValueError, NotImplementedError) as e:
    logger.error("bad permission path: %s", e)
    raise

Prevention

When it happens

Trigger: Constructing FilesystemPermission with '~' or '~/foo' (or a segment exactly '~') in the path pattern.

Common situations: Copying shell-style rules like '~/.ssh/**' into permission config; expanding user home paths lazily instead of via os.path.expanduser at config time.

Related errors


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