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
- Read the embedded cause: 'Resource busy' - quit GitButler and retry; 'Permission denied' - fix ownership of the install dir; ENOSPC - free space
- Re-run the installer once the cause is addressed; the old version keeps working meanwhile
- 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
- Quit the desktop app before CLI-driven updates
- Check free disk space on the install volume before updating
- Read the embedded rename error to fix the real blocker before retrying
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
- Failed to install new version: {}. Also failed to restore ba
- Failed to move new installation into place: {e}
- Failed to create symlink: {e}. Previous installation was res
- Installation failed but your previous installation was resto
- New installation verification failed - 'but' binary cannot r
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/591fc85aa32dbe13.
Report an issue: GitHub.