gitbutlerapp/gitbutler · critical

Installation failed and backup restoration also failed - 'bu

Error message

Installation failed and backup restoration also failed - 'but' command may not work

What it means

Critical macOS rollback failure: final validation of the new install failed, the backup app was moved back, but the restored setup also fails validation - or one of the restore steps itself errored, since the symlink recreate uses '?'. Both new and old binaries now fail to execute, pointing at a system-level execution problem rather than a bad artifact.

Source

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

        }
    }

    if !validate_installed_binary(&but_symlink) {
        // Try to restore backup
        warn("Final installation verification failed - attempting to restore backup");
        if install_app_backup.exists() {
            fs::remove_dir_all(&install_app)?;
            fs::rename(&install_app_backup, &install_app)?;

            let restored_target = install_app.join("Contents/MacOS/gitbutler-tauri");
            let _ = fs::remove_file(&but_symlink);
            unix_fs::symlink(&restored_target, &but_symlink)?;

            if validate_installed_binary(&but_symlink) {
                success("Backup was restored successfully");
                bail!("Installation failed but your previous installation was restored");
            } else {
                bail!(
                    "Installation failed and backup restoration also failed - 'but' command may not work"
                );
            }
        } else {
            bail!("Installation failed and no backup available to restore");
        }
    }

    success(&format!(
        "{} installed successfully",
        app_basename.to_string_lossy()
    ));
    // Remove backup on success
    let _ = fs::remove_dir_all(&install_app_backup);

    success("GitButler CLI (but) installed successfully");

    Ok(())

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Test both directly: /Applications/GitButler.app/Contents/MacOS/gitbutler-tauri --version and ~/.local/bin/but --version; read the concrete error
  2. If the symlink is broken, recreate it: ln -sf /Applications/GitButler.app/Contents/MacOS/gitbutler-tauri ~/.local/bin/but
  3. Clear quarantine on the restored app: xattr -dr com.apple.quarantine /Applications/GitButler.app, then re-validate
  4. If binaries still will not run, fix the OS-level cause (Gatekeeper allow, MDM exemption) before reinstalling
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe that both the app binary and the bin dir are usable before updating
let app_ok = std::process::Command::new(
        install_app.join("Contents/MacOS/gitbutler-tauri"))
    .arg("--version").stdout(std::process::Stdio::null())
    .stderr(std::process::Stdio::null()).status()
    .is_ok_and(|s| s.success());
anyhow::ensure!(app_ok, "existing app binary no longer executes; fix before updating");
std::fs::create_dir_all(home.join(".local/bin"))?;

Try / catch

if let Err(e) = but_installer::run_installation_with_version(request, false) {
    if e.to_string().contains("backup restoration also failed") {
        // drive manual repair: recreate symlink, clear quarantine, reinstall
        std::os::unix::fs::symlink(
            install_app.join("Contents/MacOS/gitbutler-tauri"),
            home.join(".local/bin/but"))?;
        let _ = std::process::Command::new("xattr")
            .args(["-dr", "com.apple.quarantine"]).arg(&install_app).status();
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Gatekeeper/MDM policy now blocks both binaries (quarantine re-applied, policy tightened mid-update); the OS lost runtime pieces an update removed; the restored symlink could not be recreated because the link path became unwritable mid-flight.

Common situations: macOS security update re-evaluating existing binaries; MDM pushing a blocking policy during the update window; disk or permission corruption.

Related errors


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