gitbutlerapp/gitbutler · error

Failed to install new version: {e}. Previous installation re

Error message

Failed to install new version: {e}. Previous installation restored successfully.

What it means

The rename moving the new .app into the install location failed, but a backup existed and was restored successfully - the previous GitButler version is back in place. The original fs::rename error is embedded in the message, so the underlying cause (busy target, permissions, disk full) is still visible. This is the benign twin of the both-renames-failed critical branch.

Source

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

    }

    // Move new installation into place with rollback on failure
    if let Err(e) = fs::rename(&install_app_new, &install_app) {
        // Clean up stale artifacts before handling the error
        cleanup_artifacts();

        // Critical failure - restore backup if we created one
        if had_backup && install_app_backup.exists() {
            warn("Failed to move new installation into place - restoring backup");
            if let Err(restore_err) = fs::rename(&install_app_backup, &install_app) {
                bail!(
                    "Failed to install new version: {}. Also failed to restore backup: {}. Your app may be at {}",
                    e,
                    restore_err,
                    install_app_backup.display()
                );
            }
            bail!(
                "Failed to install new version: {e}. Previous installation restored successfully."
            );
        }
        // No backup to restore, just fail
        bail!("Failed to move new installation into place: {e}");
    }

    // Update the symlink to point to the new installation
    let final_target = install_app.join("Contents/MacOS/gitbutler-tauri");
    let _ = fs::remove_file(&but_symlink);

    // Try to create symlink and verify - if either fails, rollback
    let symlink_result = unix_fs::symlink(&final_target, &but_symlink);
    let _ = fs::remove_file(&but_new);

    if let Err(e) = symlink_result {
        // Symlink creation failed - rollback to backup
        warn(&format!(

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Read the embedded cause: 'Resource busy' - quit GitButler and retry; 'Permission denied' - fix ownership of the install dir; ENOSPC - free space
  2. Re-run the installer once the cause is addressed; the old version keeps working meanwhile
  3. df -h the install volume to rule out disk full
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-check the two usual rename blockers: running app and free space
let running = app_process_running()?; // pgrep gitbutler-tauri
anyhow::ensure!(!running, "quit GitButler before updating");
anyhow::ensure!(free_bytes(&install_dir)? > 2 * bundle_size, "not enough disk space to swap");

Try / catch

match but_installer::run_installation_with_version(request, false) {
    Err(e) if e.to_string().contains("Previous installation restored successfully") => {
        // old version is live again; safe to retry after the user quits the app
        log::info!("update rolled back; retry after quitting GitButler");
    }
    result => result,
}

Prevention

When it happens

Trigger: fs::rename of the staged app fails with EBUSY (app running), EACCES (install dir not writable), or ENOSPC (disk full); the backup rename back then succeeds because the cause was transient or specific to the staged path.

Common situations: Updating with the desktop app open; non-admin /Applications; temporary disk pressure that eased between the two renames.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/591fc85aa32dbe13. Report an issue: GitHub.