farion1231/cc-switch · error · anyhow::Error
Skill 存储目录不能与 {app:?} 的 Skills 目录相同: {}
Error message
Skill 存储目录不能与 {app:?} 的 Skills 目录相同: {} What it means
Chinese-language guard in CC Switch's Rust skill service: ensure_distinct_skill_roots (src-tauri/src/services/skill.rs:667-675) rejects a configuration where the SSOT skill storage directory is the same path as the target app's Skills directory. 'Same' means literal equality or both paths canonicalizing to the same real path (paths_alias, line 631-640), which catches symlinks. The guard protects sync_to_app_dir from copying a directory into itself and two apps from deleting the same entries through aliased roots. Rendered message: 'Skill 存储目录不能与 {app} 的 Skills 目录相同: {ssot_dir}' (Skill storage directory must not equal the app's Skills directory).
Source
Thrown at src-tauri/src/services/skill.rs:669
if overlaps(&left, &right) {
return true;
}
}
// canonicalize() follows the final component and therefore fails for a
// dangling symlink. Resolve the parents separately so two applications
// cannot delete the same directory entry through aliased roots.
let canonical_entry =
|path: &Path| Some(path.parent()?.canonicalize().ok()?.join(path.file_name()?));
matches!(
(canonical_entry(left), canonical_entry(right)),
(Some(left), Some(right)) if overlaps(&left, &right)
)
}
fn ensure_distinct_skill_roots(ssot_dir: &Path, app_dir: &Path, app: &AppType) -> Result<()> {
if Self::paths_alias(ssot_dir, app_dir) {
return Err(anyhow!(
"Skill 存储目录不能与 {app:?} 的 Skills 目录相同: {}",
ssot_dir.display()
));
}
Ok(())
}
fn get_distinct_app_skills_dir(ssot_dir: &Path, app: &AppType) -> Result<PathBuf> {
let app_dir = Self::get_app_skills_dir(app)?;
Self::ensure_distinct_skill_roots(ssot_dir, &app_dir, app)?;
Ok(app_dir)
}
fn validate_skill_storage_destination(ssot_dir: &Path) -> Result<()> {
for app in AppType::all() {
if matches!(app, AppType::ClaudeDesktop) {
continue;
}View on GitHub (pinned to a2e22f3302)
Solutions
- Change one side: pick a different skill storage location, or point the app override dir somewhere other than the SSOT root (e.g. keep Claude at ~/.claude instead of ~/.agents)
- Remove symlinks between the SSOT directory and any app skills directory so canonical paths differ
- Audit settings.json override keys (claude/codex/gemini/grok/opencode/openclaw/hermes) and the Pi agent dir after the error names the colliding app
- Keep CC Switch's managed layout: SSOT under ~/.cc-switch/skills (or ~/.agents/skills) and let sync project into each app's own skills dir
Example fix
// before (settings.json — app skills dir aliases the unified SSOT dir)
{ "claudeOverrideDir": "~/.agents" }
// -> ~/.agents/skills == SSOT ~/.agents/skills -> error
// after
{ "claudeOverrideDir": "~/.claude" } Defensive patterns
Strategy: try-catch
Try / catch
match SkillService::get_distinct_app_skills_dir(&ssot_dir, &app) {
Ok(dir) => { /* proceed with sync */ }
Err(e) if e.to_string().contains("Skill 存储目录不能与") => {
// storage location collides with the app's skills dir: fix settings, do not retry blindly
prompt_user_to_change_storage_location_or_override_dir();
}
Err(e) => return Err(e),
} Prevention
- Never point an app override dir (claude/codex/gemini/...) at ~/.agents or ~/.cc-switch — its skills/ child then aliases the SSOT dir
- Keep the managed layout: SSOT owns ~/.cc-switch/skills or ~/.agents/skills, apps own their own skills dirs
- Avoid symlinking app skills dirs to the SSOT dir; canonicalization detects it
- After changing skill storage location, run a sync once to surface collisions early
When it happens
Trigger: SkillStorageLocation::Unified resolves to ~/.agents/skills while an app override dir (e.g. claude_override_dir) is set to ~/.agents, making the app's skills dir identical to the SSOT dir; or a symlink from ~/.claude/skills pointing at ~/.cc-switch/skills; also hit from validate_skill_storage_destination which loops over all AppTypes when changing storage location.
Common situations: Users try to 'share' one folder between CC Switch and Claude/Codex to save disk; Pi agent dir configured to ~/.agents; migrating storage location while overrides from earlier experiments are still set in settings.json; symlink-based dotfile management.
Related errors
- Skill directory changed during install; please retry
- Unsupported URL scheme
- Invalid URL
- SKILL_DIRECTORY_CONFLICT
- INVALID_SKILL_DIRECTORY
AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16).
Data as JSON: /api/errors/002346839a3b760e.
Report an issue: GitHub.