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

  1. Check the error output of running `but_new` manually at the staging path for the real reason.
  2. Remove quarantine if appropriate: `xattr -dr com.apple.quarantine <path to new app/binary>`, then retry.
  3. Verify you downloaded the correct architecture artifact (aarch64 vs x86_64) and install Rosetta 2 (`softwareupdate --install-rosetta`) if needed.
  4. Re-download — corrupted artifacts fail exec; retry the install to get a fresh copy.
  5. 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

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


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)