gitbutlerapp/gitbutler · warning

Could not remove quarantine attribute: {e} - macOS may show

Error message

Could not remove quarantine attribute: {e} - macOS may show security warnings

What it means

The macOS installer strips the com.apple.quarantine extended attribute from the staged app bundle (remove_quarantine_recursive) so Gatekeeper does not treat the CLI-installed app as a blocked download. If stripping fails, the install continues — the consequence is deferred to the user: macOS may show 'app can't be opened because it is from an unidentified developer', resolved via System Settings > Privacy & Security > Allow Anyway.

Source

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

            .map(|c| format!(" channel {}", c.display_name()))
            .unwrap_or_default(),
        install_app.display()
    ));

    // Clean up any leftover temp files from previous failed installations
    let _ = fs::remove_dir_all(&install_app_new);
    let _ = fs::remove_dir_all(&install_app_backup);

    // Create Applications directory if it doesn't exist
    fs::create_dir_all(home_dir.join("Applications"))?;

    // Install to temporary location first
    info("Installing to temporary location...");
    copy_dir_all(app_dir, &install_app_new)?;

    // Remove macOS quarantine attribute
    if let Err(e) = remove_quarantine_recursive(&install_app_new) {
        warn(&format!(
            "Could not remove quarantine attribute: {e} - macOS may show security warnings"
        ));
        info("If macOS blocks the app, go to System Settings > Privacy & Security and allow it");
    }

    // Create bin directory
    let bin_dir = home_dir.join(".local/bin");
    fs::create_dir_all(&bin_dir)?;

    // Check for existing 'but' and detect channel switching
    let but_symlink = bin_dir.join("but");
    let but_new = bin_dir.join("but.new");

    if but_symlink.exists() && !but_symlink.is_symlink() {
        // 'but' exists but is not a symlink
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()

View on GitHub (pinned to caf1f223d3)

Solutions

  1. If macOS blocks the app on first launch: System Settings > Privacy & Security > 'Allow Anyway'
  2. Strip the attribute manually: xattr -dr com.apple.quarantine ~/Applications/<App>.app
  3. Install Command Line Tools (xcode-select --install) and re-run the installer so removal succeeds
Defensive patterns

Strategy: fallback

Validate before calling

// Check whether the attribute is actually present before/after removal
std::process::Command::new("xattr")
    .args(["-p", "com.apple.quarantine"])
    .arg(&install_app_new)
    .output()
    .map(|o| o.status.success())
    .unwrap_or(false);

Try / catch

if let Err(e) = remove_quarantine_recursive(&install_app_new) {
    warn(&format!("Could not remove quarantine attribute: {e} - macOS may show security warnings"));
    info("If macOS blocks the app, go to System Settings > Privacy & Security and allow it");
}

Prevention

When it happens

Trigger: remove_quarantine_recursive(&install_app_new) returns Err at crates/but-installer/src/install_macos.rs:104 — the xattr tooling is missing (no Xcode Command Line Tools), some files in the bundle are not writable by the user, or SIP or MDM policy restricts attribute changes.

Common situations: A fresh Mac without Command Line Tools; bundles containing root-owned files from a previous manual install; managed or sandboxed Macs restricting xattr.

Related errors


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