farion1231/cc-switch · error · anyhow::Error
Skill 源目录缺少 SKILL.md,拒绝同步以避免覆盖目标目录: {}
Error message
Skill 源目录缺少 SKILL.md,拒绝同步以避免覆盖目标目录: {} What it means
Thrown by validate_sync_source_dir when the SSOT source directory exists but contains no SKILL.md manifest. The check is deliberate: copying an empty or half-written source over the app destination would silently wipe a working skill, so sync is refused until the source is a valid skill directory again.
Source
Thrown at src-tauri/src/services/skill.rs:2342
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()
.ok_or_else(|| anyhow!("Invalid skill destination: {}", dest.display()))?;
fs::create_dir_all(parent)?;
let nonce = SystemTime::now()
.duration_since(UNIX_EPOCH)View on GitHub (pinned to a2e22f3302)
Solutions
- Inspect the printed source path and confirm SKILL.md is missing or misnamed (e.g. skill.md, SKILL.MD)
- Restore SKILL.md (restore from backup or reinstall/re-import the skill to rewrite the whole SSOT copy)
- If the directory is junk, delete it and remove the DB row so sync stops attempting it
Example fix
// before
service.sync_to_app_dir(&directory, &app)?; // Skill 源目录缺少 SKILL.md
// after
let source = ssot_dir.join(&directory);
if !source.join("SKILL.md").is_file() {
return reinstall_skill(&directory); // repopulate manifest before syncing
}
service.sync_to_app_dir(&directory, &app)?; Defensive patterns
Strategy: validation
Validate before calling
// Rust caller — require the manifest before sync
let source = ssot_dir.join(&directory);
if !source.join("SKILL.md").is_file() {
return Err(anyhow!("skill source incomplete (no SKILL.md): {}", source.display()));
} Try / catch
match service.sync_to_app_dir(&dir, &app) {
Err(e) if e.to_string().contains("缺少 SKILL.md") => repair_or_reinstall(&dir).await,
other => other,
} Prevention
- Keep SKILL.md as the first file written during any custom packaging step
- Don't rename SKILL.md when editing skills; frontmatter edits belong inside the file
- Treat a source dir without SKILL.md as corrupt and rebuild it from the original install
When it happens
Trigger: An interrupted download/import left the SSOT directory half-populated; the user or another tool deleted SKILL.md from the SSOT folder; a directory was created manually inside SSOT that is not actually a skill.
Common situations: Disk-full during install so SKILL.md was never written; sync tools that skip the manifest file; users editing skills and accidentally renaming SKILL.md.
Related errors
- Skill 不存在于 SSOT: {directory}
- 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/6db282a3c0179f2a.
Report an issue: GitHub.