gitbutlerapp/gitbutler · critical
Failed to create symlink and failed to remove new installati
Error message
Failed to create symlink and failed to remove new installation during rollback: {}. Backup at: {} What it means
After the app swap, recreating the 'but' symlink failed; rollback then tried to remove the new app directory to put the backup back, and that removal also failed. The message reports both errors plus the backup path. Likely end state: new app installed but no working but symlink, and the previous app still sitting at the printed backup path.
Source
Thrown at crates/but-installer/src/install_macos.rs:240
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!(
"Failed to create symlink and failed to remove new installation during rollback: {}. Backup at: {}",
remove_err,
install_app_backup.display()
);
}
fs::rename(&install_app_backup, &install_app)?;
let restored_target = install_app.join("Contents/MacOS/gitbutler-tauri");
let _ = fs::remove_file(&but_symlink);
let _ = unix_fs::symlink(&restored_target, &but_symlink);
bail!("Failed to create symlink: {e}. Previous installation was restored.");
} else {
bail!("Failed to create symlink: {e}. No backup available to restore.");
}
}
if !validate_installed_binary(&but_symlink) {View on GitHub (pinned to caf1f223d3)
Solutions
- Manually finish the rollback: rm -rf the new app dir, mv '<backup path from the message>' into the install location, then ln -s <app>/Contents/MacOS/gitbutler-tauri ~/.local/bin/but
- If the new app actually runs, keep it and just recreate the symlink by hand; delete the backup
- Fix permissions on both the symlink dir and the app dir, then rerun the installer
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure the symlink directory is writable before install
let bin_dir = home.join(".local/bin");
std::fs::create_dir_all(&bin_dir)?;
let probe = bin_dir.join(".write-probe");
std::fs::write(&probe, b"")?;
std::fs::remove_file(&probe)?; Try / catch
if let Err(e) = but_installer::run_installation_with_version(request, false) {
let msg = e.to_string();
if msg.contains("failed to remove new installation during rollback") {
// manual recovery using the printed "Backup at:" path
let backup = msg.split("Backup at: ").nth(1).unwrap_or_default().trim();
manual_restore(std::path::Path::new(backup))?;
}
return Err(e);
} Prevention
- Verify write access to the but symlink directory before updating
- Quit the app before updates so bundle files are not locked
- Note the backup path pattern during updates for manual recovery
When it happens
Trigger: unix_fs::symlink fails (the but link path is occupied by a non-removable object or its directory is not writable) while simultaneously remove_dir_all on the new app dir fails (bundle files locked by a running app, SIP/MDM protection, permissions).
Common situations: App launched between swap and symlink; permissions changed on ~/.local/bin or the install dir since the last update; MDM policy blocking both operations.
Related errors
- Failed to install new version: {}. Also failed to restore ba
- Failed to create symlink: {e}. Previous installation was res
- Failed to create symlink: {e}. No backup available to restor
- Installation failed and backup restoration also failed - 'bu
- Installation failed and backup restoration also failed - 'bu
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/36dc286f24f5bb57.
Report an issue: GitHub.