gitbutlerapp/gitbutler · error
osascript exited with status {}
Error message
osascript exited with status {} What it means
Thrown by GitButler's macOS CLI installer (do_install_cli) when the osascript child that runs `ln -sf <binary> /usr/local/bin/but` with administrator privileges exits with a status other than 0 (success) or 1 (user dismissed the password prompt, which is reported separately as Code::CliInstallCancelled). The message embeds the raw exit status, or 'unknown' when osascript was killed by a signal. It means the privileged shell script itself failed, not that the user merely cancelled.
Source
Thrown at crates/but-action/src/cli.rs:91
.stderr(std::process::Stdio::inherit())
.status()
.context("Failed to run osascript")?;
if status.success() {
Ok(())
} else if status.code() == Some(1) {
// osascript exits 1 when the user dismisses the admin-privileges
// prompt. This is a benign abort, not an error — tag it with a
// dedicated Code so the frontend can react based on the code
// rather than matching on an English message.
Err(
anyhow!("osascript exited with status 1").context(ErrorContext::new_static(
Code::CliInstallCancelled,
"CLI install cancelled",
)),
)
} else {
Err(anyhow!(
"osascript exited with status {}",
status
.code()
.map(|c| c.to_string())
.unwrap_or_else(|| "unknown".into())
))
}
} else {
Err(anyhow!(
"Would probably need to run \"ln -sf '{}' '{UNIX_LINK_PATH}'\"{privilege}",
cli_path.display(),
privilege = if can_elevate_privileges {
" with root permissions"
} else {
""
}
))
}View on GitHub (pinned to 2497b8007a)
Solutions
- Inspect the embedded exit status: status 1 never reaches this error (it becomes Code::CliInstallCancelled); other non-zero statuses usually mean authentication or `ln` failed — re-run the install and enter correct admin credentials.
- Verify /usr/local/bin exists: `ls -ld /usr/local/bin`, and create it with `sudo mkdir -p /usr/local/bin` if missing.
- Create the symlink manually with the exact command shown in the sibling hint error: sudo ln -sf '<cli_path>' /usr/local/bin/but.
- Confirm the binary path returned by get_cli_path() still exists at elevation time and is not on an ephemeral/network volume.
- If osascript elevation is blocked by MDM, fall back to a user-writable PATH directory such as ~/.local/bin.
Example fix
# manual fallback (paths come from the sibling hint error) sudo mkdir -p /usr/local/bin sudo ln -sf '/Applications/GitButler.app/Contents/MacOS/tauri' /usr/local/bin/but but --version
Defensive patterns
Strategy: retry
Validate before calling
use std::path::Path;
fn osascript_elevation_likely_to_succeed() -> bool {
let link_dir = Path::new("/usr/local/bin");
link_dir.is_dir() // missing dir is the most common non-password failure
} Try / catch
match do_install_cli(InstallMode::AllowPrivilegeElevation) {
Ok(()) => Ok(()),
Err(err) if matches!(err.downcast_ref::<but_error::ErrorContext>().map(|c| c.code), Some(but_error::Code::CliInstallCancelled)) => Ok(()), // user dismissed prompt: not an error
Err(err) => {
// real osascript failure: offer the manual `ln -sf` command, allow one retry
Err(err)
}
} Prevention
- Ensure /usr/local/bin exists before triggering the installer.
- Keep the app binary at a stable absolute path so the elevated ln target stays valid.
- Treat exit status 1 as user cancellation (Code::CliInstallCancelled) and never surface it as a failure.
When it happens
Trigger: Calling do_install_cli(InstallMode::AllowPrivilegeElevation) on macOS after the unprivileged symlink attempt failed: the code runs /usr/bin/osascript -e 'do shell script "ln -sf ... /usr/local/bin/but" with administrator privileges' and the child exits with a code other than 0/1 — wrong admin password entered until osascript gives up, /usr/local/bin missing, `ln` failing (invalid binary path, busy target), or osascript terminated by a signal.
Common situations: Fresh macOS where /usr/local/bin does not exist (Homebrew lives in /opt/homebrew); user mistypes the admin password repeatedly; the app binary moved or was deleted between discovery and elevation; corporate MDM blocking osascript privilege escalation.
Related errors
- CliInstallCancelled
- Would probably need to run "ln -sf '{}' '{UNIX_LINK_PATH}'"{
- DefaultTerminalNotFound
- failed to open {paths:?} with app bundle identifier '{}'
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/680b930637d1f9cb.
Report an issue: GitHub.