clash-verge-rev/clash-verge-rev · error

Backup file already exists: {file_name}

Error message

Backup file already exists: {file_name}

What it means

import_local_backup computes the target path inside the local backup directory and checks if it already exists. If a file with the same name is already present, the import is rejected to avoid silent overwrite. The check runs after the same-path short-circuit, so it only fires for genuinely conflicting copies.

Source

Thrown at src-tauri/src/feat/backup.rs:214

    let file_name = source_path
        .file_name()
        .and_then(|name| name.to_str())
        .ok_or_else(|| anyhow!("Invalid backup file name"))?;

    let backup_dir = local_backup_dir()?;
    let target_path = backup_dir.join(file_name);

    if target_path == source_path {
        // Already located in the backup directory
        return Ok(file_name.to_string().into());
    }

    if let Some(parent) = target_path.parent() {
        fs::create_dir_all(parent).await?;
    }

    if target_path.exists() {
        return Err(anyhow!("Backup file already exists: {file_name}"));
    }

    fs::copy(&source_path, &target_path)
        .await
        .map_err(|err| anyhow!("Failed to import backup file: {err:#?}"))?;

    Ok(file_name.to_string().into())
}

async fn move_file(from: PathBuf, to: PathBuf) -> Result<()> {
    if let Some(parent) = to.parent() {
        fs::create_dir_all(parent).await?;
    }

    match fs::rename(&from, &to).await {
        Ok(_) => Ok(()),
        Err(rename_err) => {
            // Attempt copy + remove as fallback, covering cross-device moves

View on GitHub (pinned to 5cad0f2799)

Solutions

  1. Delete or rename the existing local backup before re-importing.
  2. Offer the user a choice: skip, overwrite, or keep-both (auto-suffix the new name).
  3. Auto-generate a unique name (append a counter/timestamp) when a conflict is detected.
  4. Check for conflicts in the UI before the import call.

Example fix

// before
if target_path.exists() {
    return Err(anyhow!("Backup file already exists: {file_name}"));
}

// after: auto-generate a non-conflicting name
let mut target_path = backup_dir.join(file_name);
if target_path.exists() {
    let stem = source_path.file_stem().and_then(|s| s.to_str()).unwrap_or("backup");
    let new_name = format!("{}-{}.zip", stem, chrono::Utc::now().timestamp());
    target_path = backup_dir.join(&new_name);
}
Defensive patterns

Strategy: validation

Validate before calling

fn target_unique(backup_dir: &PathBuf, file_name: &str) -> Result<PathBuf> {
    let target = backup_dir.join(file_name);
    if target.exists() { anyhow::bail!("Backup file already exists: {file_name}"); }
    Ok(target)
}

Type guard

fn target_is_free(backup_dir: &PathBuf, file_name: &str) -> bool {
    !backup_dir.join(file_name).exists()
}

Try / catch

if target_path.exists() {
    // offer: skip / overwrite / keep-both (auto-suffix)
    let new_name = format!("{}-{}.zip", stem, timestamp());
    target_path = backup_dir.join(new_name);
}

Prevention

When it happens

Trigger: A backup with the same file_name is already in the local backup directory (local_backup_dir), and the source is a different path; e.g. importing 'backup-2024-01-01.zip' when one already exists locally.

Common situations: Re-importing a previously imported backup; two sources share a filename; the user exported then tries to re-import the same archive; clock-skew produced duplicate timestamped names.

Related errors


AI-assisted analysis of clash-verge-rev/clash-verge-rev@5cad0f2799 (2026-08-12). Data as JSON: /api/errors/52adcf12b2d953d7. Report an issue: GitHub.