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

Pi 中的 Skill 已在操作期间发生变化,拒绝覆盖: {directory}

Error message

Pi 中的 Skill 已在操作期间发生变化,拒绝覆盖: {directory}

What it means

refresh_pi_skill_destination recorded the deployment as Symlink during inspection, but at refresh time is_symlink(destination) is false — something replaced the symlink with a regular file or directory between the two checks (time-of-check/time-of-use). The service aborts instead of blind-removing the new occupant.

Source

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

    ) -> Result<()> {
        match Self::inspect_pi_skill_destination(source, destination, directory)? {
            Some(_) => Self::remove_path(destination),
            None => Ok(()),
        }
    }

    fn refresh_pi_skill_destination(
        source: &Path,
        destination: &Path,
        directory: &str,
        deployment: &PiSkillDeployment,
    ) -> Result<()> {
        Self::validate_sync_source_dir(source, directory)?;

        match deployment {
            PiSkillDeployment::Symlink { expected_target } => {
                if !Self::is_symlink(destination) {
                    return Err(anyhow!(
                        "Pi 中的 Skill 已在操作期间发生变化,拒绝覆盖: {directory}"
                    ));
                }
                let target = fs::read_link(destination)?;
                let resolved = if target.is_absolute() {
                    target
                } else {
                    destination
                        .parent()
                        .map(|parent| parent.join(&target))
                        .unwrap_or(target)
                };
                if &resolved != expected_target {
                    return Err(anyhow!(
                        "Pi 中的 Skill 已在操作期间发生变化,拒绝覆盖: {directory}"
                    ));
                }
                Self::remove_path(destination)?;

View on GitHub (pinned to 0b5da51016)

Solutions

  1. Retry the operation — it re-inspects current state and will classify the new occupant correctly
  2. If it persists, inspect the Pi-side path manually and resolve the conflict (see error 56 guidance)
  3. Run only one app instance and avoid editing Pi's skills directory during syncs
Defensive patterns

Strategy: retry

Try / catch

try {
  await invoke('update_skill', { id });
} catch (e) {
  if (String(e).includes('在操作期间发生变化')) {
    await sleep(500);
    return invoke('update_skill', { id }); // re-inspect resolves the new state
  }
  throw e;
}

Prevention

When it happens

Trigger: The Pi app or a user rewrote the destination path while an install/update/sync was between its inspect and refresh phases; two concurrent sync operations retargeting the same Pi path.

Common situations: Long-running syncs on slow disks; Pi running simultaneously and rewriting its skills dir; concurrent app instances.

Related errors


AI-assisted analysis of farion1231/cc-switch@0b5da51016 (2026-08-20). Data as JSON: /api/errors/b538bf538edd23a3. Report an issue: GitHub.