langchain-ai/deepagents · error · SystemExit

Error: Cannot determine base skills directory. Refusing to d

Error message

Error: Cannot determine base skills directory. Refusing to delete.

What it means

A matching skill was found, but its declared `source` does not map to an available base directory (`project_skills_dir` or `user_skills_dir` is None). The command cannot establish a containment root, so it refuses to delete rather than remove a path it cannot verify is inside a skills directory.

Source

Thrown at libs/code/deepagents_code/skills/commands.py:755

    if not skill:
        console.print(f"[bold red]Error:[/bold red] Skill '{skill_name}' not found.")
        console.print("\n[dim]Available skills:[/dim]", style=theme.MUTED)
        for s in skills:
            source_tag = "[project]" if s["source"] == "project" else "[user]"
            console.print(f"  - {s['name']} {source_tag}", style=theme.MUTED)
        raise SystemExit(1)

    skill_path = Path(skill["path"])
    skill_dir = skill_path.parent

    # Validate the path is safe to delete
    base_dir = project_skills_dir if skill["source"] == "project" else user_skills_dir
    if not base_dir:
        console.print(
            "[bold red]Error:[/bold red] Cannot determine base skills directory. "
            "Refusing to delete."
        )
        raise SystemExit(1)
    is_valid_path, path_error = _validate_skill_path(skill_dir, base_dir)
    if not is_valid_path:
        console.print(f"[bold red]Error:[/bold red] {path_error}")
        raise SystemExit(1)

    if dry_run:
        if output_format == "json":
            from deepagents_code.output import write_json

            write_json(
                "skills delete",
                {
                    "name": skill_name,
                    "path": str(skill_dir),
                    "dry_run": True,
                },
            )
            return

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Re-run the delete from the correct project root so both the skill and its base dir resolve
  2. Check that the user skills directory (e.g. `~/.config/.../skills`) exists and is resolvable
  3. Verify the skill's source tag via `dcode skills list` and use the matching scope flag

Example fix

// before
dcode skills delete my-skill --project   # project skills dir no longer exists
// after
cd ~/work/my-project && mkdir -p .claude/skills && dcode skills delete my-skill --project
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def base_dir_available(source: str, project_root: str) -> bool:
    if source == "project":
        return (Path(project_root) / ".claude" / "skills").is_dir()
    return Path.home().joinpath(".claude", "skills").is_dir()

assert base_dir_available("project", ".")

Type guard

def resolvable_base(source: str, project_root: str | None) -> bool:
    if source == "project":
        return bool(project_root) and (Path(project_root) / ".claude" / "skills").is_dir()
    return (Path.home() / ".claude" / "skills").is_dir()

Prevention

When it happens

Trigger: `skill["source"] == "project"` but `project_skills_dir` is falsy (e.g. the skills dir was deleted between listing and deletion), or source is user-scoped while `user_skills_dir` is unavailable.

Common situations: Stale state where the project root/skills dir changed mid-session, `XDG`/home resolution failing for user skills, or custom skill sources not matching either base directory.

Related errors


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