gitbutlerapp/gitbutler · error
Failed to move new installation into place
Error message
Failed to move new installation into place: {e} What it means
The atomic swap rename of the new .app into place failed and there was no previous installation to restore (had_backup was false, i.e. no GitButler.app existed yet). The installer bails with just the underlying rename error, leaving the system without an installed app (stale artifacts were already cleaned up).
Solutions
- Remove any partial directory at the install path (`rm -rf` the leftover GitButler.app) and retry
- Check the destination is writable: `ls -ld` the install parent dir; fix ownership/permissions
- Free disk space (`df -h`) if the disk is full
- Ensure no process holds the destination path open, then rerun the installer
Example fix
// before: blindly retrying
installer::download_and_install_app(...)?;
// after: precheck target path is clear
let target = home.join("Applications/GitButler.app");
if target.exists() && !target.symlink_metadata()?.is_dir() {
bail!("unexpected file at {} - remove it before installing", target.display());
} Defensive patterns
Strategy: validation
Validate before calling
let target = home.join("Applications/GitButler.app");
if target.exists() {
bail!("stale path {} blocks install - remove it first", target.display());
}
let test = home.join("Applications/.write-test");
fs::write(&test, b"x").map_err(|e| format!("install dir not writable: {e}"))?;
let _ = fs::remove_file(&test); Try / catch
match result {
Err(e) if e.to_string().contains("Failed to move new installation into place") => {
eprintln!("check permissions/disk space at install path, then retry: {e}");
}
other => other?,
} Prevention
- Run installs as the owning user, never sudo
- Delete partial installs from failed attempts before retrying
- Check `df -h` free space on the target volume before updating
When it happens
Trigger: install_app (via download_and_install_app) on a fresh machine (no existing install) when fs::rename(&install_app_new, &install_app) fails: destination volume read-only, permissions problem, disk full, or a non-empty directory already occupies the target path from a partially deleted install.
Common situations: First-ever CLI install on a locked-down corporate Mac; ~/Applications is not writable; leftover partial GitButler.app directory from a crashed previous install blocks the rename.
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 install new version
- Failed to create symlink and failed to remove new…
- Failed to create symlink
- Failed to create symlink
- Installation failed and no backup available to restore
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/a27d1d78b27f1bef.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-installer/src/install_macos.rs:222
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!(
"Failed to create symlink: {e} - attempting to restore backup"
));
if install_app_backup.exists() {
if let Err(remove_err) = fs::remove_dir_all(&install_app) {
bail!(View on GitHub (pinned to 58e5313667)