farion1231/cc-switch · error · anyhow::Error

Invalid skill destination: {}

Error message

Invalid skill destination: {}

What it means

Thrown by replace_dest_with_copy when dest.parent() returns None, i.e. the computed destination path is a filesystem root with no parent component. This is a defensive assertion: dest is always app_dir.join(directory), so reaching it requires the app skills directory to have degenerated to a root-level path.

Source

Thrown at src-tauri/src/services/skill.rs:2356

        }

        let manifest = source.join("SKILL.md");
        if !manifest.is_file() {
            return Err(anyhow!(
                "Skill 源目录缺少 SKILL.md,拒绝同步以避免覆盖目标目录: {}",
                source.display()
            ));
        }

        Ok(())
    }

    fn replace_dest_with_copy(source: &Path, dest: &Path, directory: &str) -> Result<()> {
        Self::validate_sync_source_dir(source, directory)?;

        let parent = dest
            .parent()
            .ok_or_else(|| anyhow!("Invalid skill destination: {}", dest.display()))?;
        fs::create_dir_all(parent)?;

        let nonce = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_default()
            .as_nanos();
        let tmp_name = Self::sanitize_backup_segment(directory);
        let tmp = parent.join(format!(".{tmp_name}.tmp-{}-{nonce}", std::process::id()));

        if tmp.exists() || Self::is_symlink(&tmp) {
            Self::remove_path(&tmp)?;
        }

        let copy_result = Self::copy_dir_recursive(source, &tmp);
        if let Err(err) = copy_result {
            let _ = Self::remove_path(&tmp);
            return Err(err);
        }

View on GitHub (pinned to a2e22f3302)

Solutions

  1. Print/log dest.display() from the error and check what the app skills directory resolved to
  2. Fix the app skills directory setting back to a normal absolute directory (e.g. ~/.claude/skills)
  3. If it reproduces with valid settings, file a bug against get_distinct_app_skills_dir path handling
Defensive patterns

Strategy: validation

Validate before calling

// Rust caller — sanity-check the app skills dir setting before sync
let app_dir = SkillService::get_distinct_app_skills_dir(&ssot, &app)?;
if app_dir.parent().is_none() || app_dir == Path::new("/") {
    return Err(anyhow!("app skills dir misconfigured: {}", app_dir.display()));
}

Prevention

When it happens

Trigger: A custom/misconfigured app skills directory that resolves to "/" or an empty path, making dest a root path. Not reachable through normal configuration where app_dir is a normal absolute directory.

Common situations: Manually edited settings pointing the app skills dir at a filesystem root; a path-resolution regression in get_distinct_app_skills_dir. Practically never seen in the wild.

Related errors


AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16). Data as JSON: /api/errors/d7e2e44eea53775f. Report an issue: GitHub.