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

Skill 不存在于 SSOT: {directory}

Error message

Skill 不存在于 SSOT: {directory}

What it means

Thrown by SkillService::validate_sync_source_dir during sync_to_app_dir: the skill's source directory under the SSOT store (single source of truth) does not exist or is not a directory, so the service refuses to propagate anything to the app's skills folder. It fails before any destination write, so the app-side copy is never touched. The {directory} placeholder is the install name stored in the installed_skills DB row.

Source

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

        if Self::is_symlink(path) {
            // 符号链接:仅删除链接本身,不影响源文件
            #[cfg(unix)]
            fs::remove_file(path)?;
            #[cfg(windows)]
            fs::remove_dir(path)?; // Windows 的目录 symlink 需要用 remove_dir
        } else if path.is_dir() {
            // 真实目录:递归删除
            fs::remove_dir_all(path)?;
        } else if path.exists() {
            // 普通文件
            fs::remove_file(path)?;
        }
        Ok(())
    }

    fn validate_sync_source_dir(source: &Path, directory: &str) -> Result<()> {
        if !source.is_dir() {
            return Err(anyhow!("Skill 不存在于 SSOT: {directory}"));
        }

        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()

View on GitHub (pinned to a2e22f3302)

Solutions

  1. Resolve the SSOT dir (SkillService::get_ssot_dir) and check whether <ssot>/<directory> exists; if it was moved, move it back or update the setting
  2. If the files are gone, reinstall or re-import the skill so the SSOT copy is repopulated before syncing
  3. If the DB row is stale (skill really removed), uninstall the skill / delete the row so sync attempts stop

Example fix

// before
service.sync_to_app_dir(&directory, &app)?; // errors: Skill 不存在于 SSOT

// after
let source = SkillService::get_ssot_dir()?.join(&directory);
if !source.is_dir() {
    // prompt user to reinstall / re-import the skill instead of failing sync
    return reinstall_skill(&directory);
}
service.sync_to_app_dir(&directory, &app)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust caller — verify SSOT source exists before requesting a sync
let ssot = SkillService::get_ssot_dir()?;
let source = ssot.join(&directory);
if !source.is_dir() {
    // trigger reinstall / re-import flow instead of letting sync fail
    return Err(anyhow!("skill missing from SSOT: {}", source.display()));
}

Try / catch

match service.sync_to_app_dir(&dir, &app) {
    Err(e) if e.to_string().contains("Skill 不存在于 SSOT") => reinstall_skill(&dir).await,
    other => other,
}

Prevention

When it happens

Trigger: Calling sync_to_app_dir(directory, app) for a skill whose SSOT folder <ssot_dir>/<directory> was deleted, moved, or never created: files removed manually in the file manager, a cleaner/antivirus wiped app data, an interrupted install left a DB row without files, or the SSOT location setting changed after the skill was installed.

Common situations: DB restored from a WebDAV remote snapshot but SSOT files not yet materialized; user reorganized the SSOT directory by hand; partial uninstall; app-data migration between machines copying the SQLite DB but not the skills folder.

Related errors


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