gitbutlerapp/gitbutler · critical
Failed to move new installation into place - restoring…
Error message
Failed to move new installation into place - restoring backup
What it means
install_app on macOS moves the staged new .app bundle into /Applications with fs::rename. When that rename fails, the installer warns that it is restoring the backup of the previous installation, then tries rename(backup, install_app). If the restore also fails it bails with a combined message naming both errors and where the backup lives.
Solutions
- Quit the running app (and any helper processes) and retry the install.
- Re-run the installer with elevated privileges (sudo) so it can replace the bundle in /Applications.
- Check that the backup path printed in the bail message still contains your old app and restore it manually if needed.
- Ensure temp staging and /Applications are on the same volume, or copy instead of rename when crossing devices.
- Free disk space if the rename failed due to insufficient space during cross-device copy.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight checks before install
import subprocess, os
def can_install(app_path):
if os.path.exists(app_path):
try:
os.rename(app_path, app_path + '.probe')
os.rename(app_path + '.probe', app_path)
except OSError as e:
return False, f'Cannot rename target: {e}'
return os.access(os.path.dirname(app_path), os.W_OK), None Try / catch
// Rust pattern: check rename result and preserve backup path on failure
if let Err(e) = fs::rename(&install_app_new, &install_app) {
if let Err(re) = fs::rename(&install_app_backup, &install_app) {
bail!("install failed: {e}; restore failed: {re}; backup at {}", install_app_backup.display());
}
} Prevention
- Quit the app before upgrading so the bundle is not locked
- Ensure /Applications is writable (admin rights) and the temp dir is on the same volume
- Keep enough free disk space for both old and new bundles
- Never delete the .backup bundle until the new version is verified
When it happens
Trigger: Raised in install_app (called from download_and_install_app) when fs::rename(&install_app_new, &install_app) fails — e.g. /Applications/App.app is locked by a running process, or the destination sits on a different volume so rename must copy cross-device and fails.
Common situations: The app is running and macOS holds the bundle open; permission issues on /Applications without admin rights; the target volume differs from the temp dir (cross-filesystem rename not supported); antivirus/quarantine tooling locking the bundle.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Failed to create symlink
- A 'but' binary already exists at
- Cannot write to ( )
- Could not remove quarantine attribute
- Could not resolve application path for
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/2770059f00144b18.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-installer/src/install_macos.rs:208
let _ = fs::remove_file(&but_new);
};
// Backup existing installation if it exists
let had_backup = install_app.exists();
if had_backup && let Err(e) = fs::rename(&install_app, &install_app_backup) {
// Failed to backup - clean up artifacts before failing
cleanup_artifacts();
return Err(e.into());
}
// 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");View on GitHub (pinned to 58e5313667)