gitbutlerapp/gitbutler · error

osascript directory picker failed (exit {:?}): {}

Error message

osascript directory picker failed (exit {:?}): {}

What it means

The macOS directory picker in but-server shells out to osascript running 'choose folder'. A non-zero exit whose stderr is not one of the user-cancel markers ('User canceled' or error -128) is treated as a real failure and bailed with the exit code and stderr; an actual user cancel returns Ok(None).

Source

Thrown at crates/but-server/src/lib.rs:129

/// Shell out to a platform-native directory picker.
fn native_pick_directory() -> anyhow::Result<Option<String>> {
    #[cfg(target_os = "macos")]
    {
        let output = std::process::Command::new("osascript")
            .arg("-e")
            .arg(
                r#"set theFolder to choose folder with prompt "Select a Git repository"
return POSIX path of theFolder"#,
            )
            .output()?;
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
            // osascript exits with code 1 and "User canceled" on cancel
            if stderr.contains("User canceled") || stderr.contains("(-128)") {
                return Ok(None);
            }
            anyhow::bail!(
                "osascript directory picker failed (exit {:?}): {}",
                output.status.code(),
                if stderr.is_empty() {
                    "unknown error"
                } else {
                    &stderr
                }
            );
        }
        let path = String::from_utf8_lossy(&output.stdout).trim().to_string();
        if path.is_empty() {
            return Ok(None);
        }
        // osascript returns paths with a trailing slash — strip it
        Ok(Some(path.trim_end_matches('/').to_string()))
    }

    #[cfg(target_os = "linux")]

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Grant the hosting app/terminal Automation permission for Finder/System Events (System Settings > Privacy & Security > Automation)
  2. Run the picker from a normal GUI session, not SSH or a daemon context
  3. Inspect the exit code and stderr embedded in the message to identify the AppleScript failure
Defensive patterns

Strategy: fallback

Validate before calling

// Rust: probe osascript availability before offering the native picker
let available = which::which("osascript").is_ok();
offer_picker = available && is_gui_session(); // DISPLAY/WindowServer present

Try / catch

Cancel already maps to Ok(None); for real failures, catch the bail, show the exit code/stderr, hint at System Settings > Privacy & Security > Automation, and fall back to a manual path input field.

Prevention

When it happens

Trigger: Running the pick-directory flow on macOS where osascript fails for reasons other than cancel: Automation/Finder permission denied to the hosting process, osascript missing or broken, or no WindowServer connection (SSH/headless).

Common situations: The app or terminal lacks Automation permission under macOS privacy settings; running the binary over SSH; corporate hardening that removes or restricts osascript.

Related errors


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