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
- 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
- If the files are gone, reinstall or re-import the skill so the SSOT copy is repopulated before syncing
- 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
- Never delete or move SSOT skill folders by hand; uninstall via the app so the DB row is removed too
- After restoring a DB from a remote snapshot, verify SSOT files are materialized before triggering sync-all
- Monitor for rows whose SSOT dir is missing and clean them up promptly
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
- Skill 源目录缺少 SKILL.md,拒绝同步以避免覆盖目标目录: {}
- Invalid skill destination: {}
- Skill 存储目录不能与 {app:?} 的 Skills 目录相同: {}
- Skill directory changed during install; please retry
- Invalid skill directory (possible path traversal): {director
AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16).
Data as JSON: /api/errors/4b4033eb68a805d4.
Report an issue: GitHub.