farion1231/cc-switch · error · anyhow::Error
Skill backup is invalid or missing SKILL.md: {}
Error message
Skill backup is invalid or missing SKILL.md: {} What it means
restore_from_backup requires backup_path/skill/SKILL.md to exist; SKILL.md is the defining artifact of a skill. Its absence means the backup is incomplete, corrupted, or was assembled by hand without the payload directory. meta.json parsed fine, but there is nothing restorable.
Source
Thrown at src-tauri/src/services/skill.rs:1768
fs::remove_dir_all(&backup_path)
.with_context(|| format!("failed to delete {}", backup_path.display()))?;
log::info!("Skill 备份已删除: {}", backup_path.display());
Ok(())
}
pub fn restore_from_backup(
db: &Arc<Database>,
backup_id: &str,
current_app: &AppType,
) -> Result<InstalledSkill> {
let _state_guard = skill_state_write_guard();
let backup_path = Self::backup_path_for_id(backup_id)?;
let metadata = Self::read_backup_metadata(&backup_path)?;
let backup_skill_dir = backup_path.join("skill");
if !backup_skill_dir.join("SKILL.md").exists() {
return Err(anyhow!(
"Skill backup is invalid or missing SKILL.md: {}",
backup_path.display()
));
}
let existing_skills = db.get_all_installed_skills()?;
if existing_skills.contains_key(&metadata.skill.id)
|| existing_skills.values().any(|skill| {
skill
.directory
.eq_ignore_ascii_case(&metadata.skill.directory)
})
{
return Err(anyhow!(
"Skill already exists, please uninstall the current one first: {}",
metadata.skill.directory
));
}View on GitHub (pinned to 0b5da51016)
Solutions
- Open the backup folder shown in the error and verify the layout: meta.json plus skill/SKILL.md
- If skill/ is missing or gutted, use a different backup or accept the skill is unrecoverable from this backup
- Delete the broken backup entry (delete_skill_backup) to clean the list, and re-create backups from live installs before uninstalling in the future
Defensive patterns
Strategy: validation
Validate before calling
const backups = await invoke<Array<{ id: string }>>('list_skill_backups');
// Prefer offering restore only for backups you did not hand-modify;
// verify the entry still exists and is recent before invoking restore.
if (!backups.some(b => b.id === backupId)) {
notify('Backup missing — refresh the backup list');
return;
} Try / catch
try {
await invoke('restore_skill_backup', { backupId, currentApp });
} catch (e) {
if (String(e).includes('missing SKILL.md')) {
notify('Backup is incomplete — use another backup or delete this entry');
return;
}
throw e;
} Prevention
- Let uninstall backups finish — do not kill the app mid-uninstall
- Never prune files inside backup folders
- Delete broken backup entries via delete_skill_backup to keep the list clean
When it happens
Trigger: Backup creation interrupted (app killed, disk full) after meta.json was written but before the skill files were copied; files inside the backup deleted afterwards; a backup folder recreated manually with only meta.json; antivirus quarantining SKILL.md.
Common situations: Crash during uninstall-backup; users pruning 'large files' inside backups; backups copied between machines with partial transfer.
Related errors
- Skill backup is not a directory: {}
- Skill already exists, please uninstall the current one first
- Restore target already exists: {}
- OPENCLAW_ENV_EMPTY
- OPENCLAW_ENV_INVALID_JSON
AI-assisted analysis of farion1231/cc-switch@0b5da51016 (2026-08-20).
Data as JSON: /api/errors/714be049aa16eca8.
Report an issue: GitHub.