gitbutlerapp/gitbutler · error
New installation verification failed - 'but' binary cannot r
Error message
New installation verification failed - 'but' binary cannot run (may be corrupted or blocked by macOS)
What it means
macOS path: before any swap, install_macos stages the extracted .app, creates a candidate 'but' symlink to its gitbutler-tauri binary, and runs 'but --version'. If that fails, the staged new install is deleted and the installer bails - the existing installation is untouched at this point. The parenthetical names the two usual causes on macOS: a corrupted binary, or Gatekeeper blocking an unnotarized/quarantined one.
Source
Thrown at crates/but-installer/src/install_macos.rs:179
}
// Create temporary symlink to test the new installation
let new_app_macos_dir = install_app_new.join("Contents/MacOS/gitbutler-tauri");
let _ = fs::remove_file(&but_new);
unix_fs::symlink(&new_app_macos_dir, &but_new)?;
// Verify the new installation works
let verify_status = Command::new(&but_new)
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
if !verify_status.map(|s| s.success()).unwrap_or(false) {
fs::remove_dir_all(&install_app_new)?;
fs::remove_file(&but_new)?;
bail!(
"New installation verification failed - 'but' binary cannot run (may be corrupted or blocked by macOS)"
);
}
// New installation is valid - now do the atomic swap
info("Swapping new installation into place...");
// Helper to clean up stale installation artifacts
let cleanup_artifacts = || {
let _ = fs::remove_dir_all(&install_app_new);
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();View on GitHub (pinned to caf1f223d3)
Solutions
- Run the extracted binary directly ( staging path or the downloaded .app: open the app once and check Privacy & Security for a block notice, then 'Allow Anyway'
- Retry the install to rule out a corrupted download
- On arm64 with an x86_64 artifact: softwareupdate --install-rosetta
- Prefer the notarized release channel over nightly on locked-down Macs
Defensive patterns
Strategy: try-catch
Validate before calling
// After manual download/extract, verify the binary executes before installing
let status = std::process::Command::new(&extracted_but)
.arg("--version")
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status();
anyhow::ensure!(status.is_ok_and(|s| s.success()), "binary blocked or corrupted"); Try / catch
match but_installer::run_installation_with_version(request, false) {
Err(e) if e.to_string().contains("New installation verification failed") => {
// check Gatekeeper/quarantine and Rosetta, then retry once
clear_quarantine_and_retry()?;
}
result => result,
} Prevention
- Allow GitButler releases in Gatekeeper/MDM policy before scripted installs
- Keep Rosetta installed on arm64 for x86_64 artifacts
- Prefer the notarized release channel on locked-down Macs
When it happens
Trigger: The staged binary exits non-zero or is killed: Gatekeeper kills an unnotarized nightly (SIGKILL before main), the downloaded bundle is corrupted, an x86_64 artifact runs on arm64 without Rosetta, or the extraction lost the executable bit.
Common situations: Nightly channel on managed Macs; corporate MDM enforcing stricter Gatekeeper; missing Rosetta 2 on Apple Silicon; CDN object corruption that still passed signature check.
Related errors
- Installation failed but your previous installation was resto
- Installation failed and backup restoration also failed - 'bu
- Installation failed and no backup available to restore
- Could not remove quarantine attribute: {e} - macOS may show
- Installation failed but your previous installation was resto
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/af12540b5b908470.
Report an issue: GitHub.