gitbutlerapp/gitbutler · info

Moving it to to preserve your existing file

Error message

Moving it to {} to preserve your existing file

What it means

Second warning in the same flow: the installer tells the user exactly where the displaced 'but' binary is being moved (but.backup.<unix-timestamp>) so their original file is preserved before the symlink replaces it. Immediately after, fs::rename performs the move.

Solutions

  1. Note the printed backup path; your original binary is intact there and can be restored with mv if needed.
  2. If the rename itself fails (logged error), move the file manually: mv <bin_dir>/but <bin_dir>/but.backup.manual and re-run the installer.
  3. Remove the stale binary if it is no longer wanted, then re-run the installer for a clean symlink.
  4. Check timestamps if multiple but.backup.* files accumulate and delete old ones you don't need.
Defensive patterns

Strategy: try-catch

Validate before calling

# Note and verify backup location after install
import glob, os
print(glob.glob(os.path.expanduser('<bin_dir>/but.backup.*')))

Try / catch

// Ensure the rename away of the old binary reports failures clearly
fs::rename(&but_symlink, &but_backup)
    .map_err(|e| anyhow!("could not preserve existing but binary: {e}"))?;

Prevention

When it happens

Trigger: Raised in install_app (download_and_install_app) right after detecting the non-symlink 'but' binary, immediately before fs::rename(&but_symlink, &but_backup); always paired with the preceding 'already exists' warning.

Common situations: Same collision scenario as the preceding warning: upgrades from copy-based installs, local builds, or package-manager-owned binaries in the target bin dir.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/27a32c2ef655a9ad. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-installer/src/install_macos.rs:130

    fs::create_dir_all(&bin_dir)?;

    // Check for existing 'but' and detect channel switching
    let but_symlink = bin_dir.join("but");
    let but_new = bin_dir.join("but.new");

    if but_symlink.exists() && !but_symlink.is_symlink() {
        // 'but' exists but is not a symlink
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();
        let timestamp = format!("{now}");
        let but_backup = bin_dir.join(format!("but.backup.{timestamp}"));
        warn(&format!(
            "A 'but' binary already exists at {} (not a symlink)",
            but_symlink.display()
        ));
        warn(&format!(
            "Moving it to {} to preserve your existing file",
            but_backup.display()
        ));
        fs::rename(&but_symlink, &but_backup)?;
        info(&format!(
            "Your original 'but' has been saved to: {}",
            but_backup.display()
        ));
    } else if but_symlink.is_symlink() {
        let existing_target = fs::read_link(&but_symlink)?;
        let existing_target_str = existing_target.to_string_lossy();

        // Detect channel switching
        let previous_channel = if existing_target_str.contains("Nightly") {
            Some(Channel::Nightly)
        } else if existing_target_str.contains("/GitButler.app/") {
            Some(Channel::Release)
        } else {

View on GitHub (pinned to 58e5313667)