{"record":{"id":"ac8305511127aee2","repo":"PrefectHQ/fastmcp","slug":"skill-directory-already-exists-skill-dir-use-o","errorCode":null,"errorMessage":"Skill directory already exists: {skill_dir}. Use overwrite=True to replace.","messagePattern":"Skill directory already exists: (.+?)\\. Use overwrite=True to replace\\.","errorType":"exception","errorClass":"FileExistsError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/utilities/skills.py","lineNumber":175,"sourceCode":"        async with Client(\"http://skills-server/mcp\") as client:\n            skill_path = await download_skill(\n                client,\n                \"pdf-processing\",\n                \"~/.claude/skills\"\n            )\n            print(f\"Downloaded to: {skill_path}\")\n        ```\n    \"\"\"\n    target_dir = Path(target_dir).expanduser().resolve()\n    skill_dir = (target_dir / skill_name).resolve()\n\n    # Security: ensure skill_dir stays within target_dir\n    if not skill_dir.is_relative_to(target_dir):\n        raise ValueError(f\"Skill name {skill_name!r} would escape the target directory\")\n\n    # Check if directory exists\n    if skill_dir.exists() and not overwrite:\n        raise FileExistsError(\n            f\"Skill directory already exists: {skill_dir}. \"\n            \"Use overwrite=True to replace.\"\n        )\n\n    # Get manifest to know what files to download\n    manifest = await get_skill_manifest(client, skill_name)\n\n    # Create skill directory\n    skill_dir.mkdir(parents=True, exist_ok=True)\n\n    # Download each file\n    for file_info in manifest.files:\n        # Security: reject absolute paths and paths that escape skill_dir\n        if Path(file_info.path).is_absolute():\n            continue\n        file_path = (skill_dir / file_info.path).resolve()\n        if not file_path.is_relative_to(skill_dir):\n            continue","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/utilities/skills.py#L157-L193","documentation":"`download_skill` refuses to overwrite an existing skill directory: if `target_dir/skill_name` already exists and `overwrite` is not True, this FileExistsError is raised. This protects previously downloaded (possibly locally modified) skills from being silently replaced.","triggerScenarios":"Calling `download_skill(client, name, dir)` a second time into the same target directory without `overwrite=True`, or a `sync_skills` run where the skill directory already exists locally from a prior download or manual creation.","commonSituations":"Re-running a sync/download script without `overwrite`, partially completed previous downloads leaving the directory behind, or a directory coincidentally named like the skill already present in the target folder.","solutions":["Pass `overwrite=True` if you intend to replace the existing skill directory.","Choose a different `target_dir` (or delete/move the existing `target_dir/skill_name`) if you want to keep the old copy.","For idempotent sync scripts, make existence of the directory the expected case and set `overwrite=True` deliberately."],"exampleFix":"// before\nawait download_skill(client, \"code-review\", \"~/skills\")  # raises if exists\n// after\nawait download_skill(client, \"code-review\", \"~/skills\", overwrite=True)","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\ndef skill_dir_conflicts(skill_name: str, target_dir: str | Path) -> bool:\n    skill_dir = (Path(target_dir).expanduser().resolve() / skill_name).resolve()\n    return skill_dir.exists()","typeGuard":null,"tryCatchPattern":"try:\n    await download_skill(client, skill_name, target_dir)\nexcept FileExistsError:\n    await download_skill(client, skill_name, target_dir, overwrite=True)  # or skip","preventionTips":["Decide up front whether your sync should overwrite, and set overwrite=True explicitly.","Use a dedicated target directory per source so stale directories don't accumulate.","Check for the existing directory before download when you need 'keep local edits' semantics."],"tags":["skills","file-exists","filesystem"],"backgroundTag":"file-already-exists","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}