langchain-ai/deepagents · error · PermissionError
Skill path {skill_path} resolves outside all allowed skill d
Error message
Skill path {skill_path} resolves outside all allowed skill directories. If this is a symlink, add the target directory to {EXTRA_SKILLS_DIRS} or [skills].extra_allowed_dirs in {config_file}. What it means
`load_skill_content` resolves the skill path and checks it against the allowlist of permitted skill roots before reading. If the resolved path escapes all allowed directories (commonly via a symlink), it raises `PermissionError` explaining how to allowlist the target directory via `EXTRA_SKILLS_DIRS` or `[skills].extra_allowed_dirs`. This is a fail-closed containment guard on skill file reads.
Source
Thrown at libs/code/deepagents_code/skills/load.py:215
from pathlib import Path
path = Path(skill_path).resolve()
if allowed_roots and not any(path.is_relative_to(root) for root in allowed_roots):
logger.warning(
"Skill path %s is outside all allowed roots, refusing to read",
skill_path,
)
from deepagents_code._env_vars import EXTRA_SKILLS_DIRS
from deepagents_code._paths import PATHS
msg = (
f"Skill path {skill_path} resolves outside all allowed skill "
"directories. If this is a symlink, add the target directory to "
f"{EXTRA_SKILLS_DIRS} or [skills].extra_allowed_dirs "
f"in {PATHS.display(PATHS.profile.config_file)}."
)
raise PermissionError(msg)
try:
return path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError):
logger.warning(
"Could not read skill content from %s", skill_path, exc_info=True
)
return None
View on GitHub (pinned to a1af029e6e)
Solutions
- If it is a symlink, add the target directory to the [skills].extra_allowed_dirs list in your config file or the EXTRA_SKILLS_DIRS setting
- Move or copy the skill physically into an allowed skills directory
- Confirm with `readlink -f <skill_path>` where the path actually resolves
- Then re-run the command; trust the directory if prompted
Example fix
// before (toml) # [skills].extra_allowed_dirs not set; ~/my-skills symlinked into skills dir // after (config.toml) [skills] extra_allowed_dirs = ["/home/me/my-skills"]
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def resolves_within(skill_path: Path, allowed_roots: list[Path]) -> bool:
resolved = skill_path.resolve()
return any(root.resolve() in resolved.parents or resolved == root.resolve()
for root in allowed_roots) Type guard
def is_contained(skill_path: Path, allowed_roots: list[Path]) -> bool:
resolved = skill_path.resolve()
return any(resolved.is_relative_to(root.resolve()) for root in allowed_roots) Try / catch
try:
content = load_skill_content(skill_path)
except PermissionError as exc:
print(f'add target dir to extra_allowed_dirs: {exc}')
raise SystemExit(1) from exc Prevention
- Run readlink -f on skill paths to see where symlinks actually point
- Register external skill locations in [skills].extra_allowed_dirs instead of symlinking
- Keep skills inside the configured project/user skills directories
- Review SKILL.md targets for paths outside the roots
When it happens
Trigger: `load_skill_content(skill_path)` (via `_load`, `_retry`, or `run_non_interactive`) when the resolved absolute path is outside every allowed skill root — including the symlink-escape case where the visible path is inside a root but its target is not.
Common situations: Skills directory symlinked to a repo elsewhere on disk; SKILL.md containing links resolved outside roots; project skills placed outside the configured project/user skills directories.
Related errors
- debug log directory is not a real directory: {path}
- Repository root must be an absolute contained path: {root!r}
- str(exc) (re-raised from resolve_bounded_media_path)
- {name}: symlink entries are not supported
- media path escapes outbound root: {path}
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/1dd09076191262dc.
Report an issue: GitHub.