gitbutlerapp/gitbutler · error
New installation verification failed - 'but' binary cannot…
Error message
New installation verification failed - 'but' binary cannot run (may be corrupted or blocked by macOS)
What it means
The macOS installer runs the newly installed `but` binary once (with stdio discarded) to prove it executes before swapping it into place. If the verification process exits non-zero or fails to spawn, the new .app contents are deleted and this error is raised — commonly because Gatekeeper quarantined the unsigned/unnotarized binary or the download was corrupted.
Solutions
- Check the error output of running `but_new` manually at the staging path for the real reason.
- Remove quarantine if appropriate: `xattr -dr com.apple.quarantine <path to new app/binary>`, then retry.
- Verify you downloaded the correct architecture artifact (aarch64 vs x86_64) and install Rosetta 2 (`softwareupdate --install-rosetta`) if needed.
- Re-download — corrupted artifacts fail exec; retry the install to get a fresh copy.
- Check System Settings → Privacy & Security for a blocked-app notice and Allow it, then retry.
Example fix
// before but upgrade # "New installation verification failed..." // after xattr -dr com.apple.quarantine /path/to/new/but softwareupdate --install-rosetta --agree-to-license # Intel binary on Apple Silicon but upgrade
Defensive patterns
Strategy: validation
Validate before calling
use std::process::Command;
fn new_binary_runs(path: &std::path::Path) -> bool {
Command::new(path).arg("--version")
.stdout(Stdio::null()).stderr(Stdio::null())
.status().map(|s| s.success()).unwrap_or(false)
}
// also check quarantine before install:
let quarantined = Command::new("xattr").args(["-p", "com.apple.quarantine"])
.arg(path).output().map(|o| o.status.success()).unwrap_or(false); Try / catch
if !new_binary_runs(&but_new) {
let _ = Command::new("xattr").args(["-dr", "com.apple.quarantine"]).arg(&install_app_new).status();
if !new_binary_runs(&but_new) {
anyhow::bail!("new but binary cannot execute even after removing quarantine");
}
} Prevention
- Strip com.apple.quarantine from downloaded artifacts before executing them.
- Verify architecture (aarch64 vs x86_64) matches the machine; install Rosetta 2 for Intel binaries on Apple Silicon.
- Test-execute the binary at the staging location before the atomic swap.
- Keep Gatekeeper/notarization status of releases in mind when automating installs on locked-down Macs.
When it happens
Trigger: macOS Gatekeeper/Translocation blocks the freshly downloaded binary (com.apple.quarantine xattr); the binary was corrupted in transit; the download is for the wrong architecture (x86_64 on Apple Silicon without Rosetta); exec permission missing.
Common situations: Installing on a locked-down corporate Mac with strict Gatekeeper policy; network middleboxes corrupting large downloads; freshly released macOS versions blocking notarization-less binaries; running on Apple Silicon without Rosetta 2 installed.
Related errors
- Could not remove quarantine attribute
- Failed to install new version
- Final installation verification failed - attempting to…
- A 'but' binary already exists at
- CLI installation failed
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/af12540b5b908470.
Report an issue: GitHub.
Appendix: 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 58e5313667)