{"record":{"id":"aa6592c94f1f440f","repo":"langchain-ai/deepagents","slug":"permission-path-must-not-contain-path-r-aa6592","errorCode":null,"errorMessage":"Permission path must not contain '~': {path!r}","messagePattern":"Permission path must not contain '~': (.+?)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"libs/deepagents/deepagents/middleware/filesystem.py","lineNumber":420,"sourceCode":"        (`ls`/`glob`/`grep`) fire the interrupt based on whether their\n        search subtree could overlap the rule's anchored prefix, so a fully\n        unanchored pattern (`/**/secrets`) collapses to `/` and\n        conservatively over-fires for any bulk call.\n    \"\"\"\n\n    def __post_init__(self) -> None:\n        \"\"\"Validate permission path patterns.\"\"\"\n        for path in self.paths:\n            if not path.startswith(\"/\"):\n                msg = f\"Permission path must start with '/': {path!r}\"\n                raise ValueError(msg)\n            parts = PurePosixPath(path.replace(\"\\\\\", \"/\")).parts\n            if \"..\" in parts:\n                msg = f\"Permission path must not contain '..': {path!r}\"\n                raise ValueError(msg)\n            if \"~\" in parts:\n                msg = f\"Permission path must not contain '~': {path!r}\"\n                raise NotImplementedError(msg)\n\n\ndef _check_fs_permission(\n    rules: list[FilesystemPermission],\n    operation: FilesystemOperation,\n    path: str,\n) -> Literal[\"allow\", \"deny\", \"interrupt\"]:\n    for rule in rules:\n        if operation not in rule.operations:\n            continue\n        if any(wcglob.globmatch(path, pattern, flags=_FS_WCMATCH_FLAGS) for pattern in rule.paths):\n            return rule.mode\n    return \"allow\"\n\n\ndef _wildcard_delete_overlap(pattern: str, anchor: str, target: str) -> bool:\n    \"\"\"Check whether a wildcard deny pattern overlaps a recursive delete target.\n","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/deepagents/deepagents/middleware/filesystem.py#L402-L438","documentation":"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.","triggerScenarios":"Constructing FilesystemPermission with '~' or '~/foo' (or a segment exactly '~') in the path pattern.","commonSituations":"Copying shell-style rules like '~/.ssh/**' into permission config; expanding user home paths lazily instead of via os.path.expanduser at config time.","solutions":["Call os.path.expanduser on the pattern before constructing the permission, then verify it still starts with '/'","Replace '~' with the concrete absolute home path","Drop '~' from config templates and document absolute paths only"],"exampleFix":"// before\nFilesystemPermission(paths=[\"~/.ssh/**\"])\n// after\nFilesystemPermission(paths=[os.path.expanduser(\"~/.ssh/**\")])","handlingStrategy":"validation","validationCode":"import os\ndef expand_tilde(p: str) -> str:\n    expanded = os.path.expanduser(p)\n    if \"~\" in expanded.split(\"/\"):\n        raise ValueError(f\"unexpandable '~' in permission path: {p!r}\")\n    return expanded","typeGuard":null,"tryCatchPattern":"try:\n    perm = FilesystemPermission(paths=[os.path.expanduser(p) for p in paths])\nexcept (ValueError, NotImplementedError) as e:\n    logger.error(\"bad permission path: %s\", e)\n    raise","preventionTips":["Always os.path.expanduser home-relative patterns before use","Document that permission patterns are absolute paths only","Validate patterns early in config loading"],"tags":["python","filesystem","configuration"],"backgroundTag":"home-path-tilde-unsupported","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}