gitbutlerapp/gitbutler · error · but_error::Code

DefaultTerminalNotFound

DefaultTerminalNotFound

Error message

'{app_name}' was not found - `open -Ra {app_name}` failed.

What it means

On macOS, launching a configured terminal first verifies the app bundle exists by running open -Ra <AppName>; a non-zero exit means the app is not installed under that name. The error carries Code::DefaultTerminalNotFound so the UI can route to a settings/installation prompt.

Source

Thrown at crates/but-api/src/open/mod.rs:408

                .map_or("unknown".to_string(), |c| c.to_string());
            if stderr.is_empty() {
                bail!("{terminal_name} exited with non-zero status: {status_code}",);
            } else {
                bail!("Failed to open {terminal_name} ({status_code}): {stderr}");
            }
        }

        /// Check if a macOS application is installed using `open -Ra`.
        fn ensure_app_installed(app_name: &str) -> Result<()> {
            let status = Command::new("open")
                .arg("-Ra")
                .arg(app_name)
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .status()
                .context("Failed to run 'open -Ra' to check application availability")?;
            if !status.success() {
                return Err(anyhow::anyhow!(
                    "'{app_name}' was not found - `open -Ra {app_name}` failed."
                )
                .context(but_error::Code::DefaultTerminalNotFound));
            }
            Ok(())
        }

        let open_with_path = |app_name: &str, alt_app_name: Option<&str>| {
            ensure_app_installed(app_name)?;
            let mut cmd = Command::new("open");
            cmd.arg("-a").arg(app_name).arg(&path);
            run_terminal_command(cmd, alt_app_name.unwrap_or(app_name), &path)
        };

        match terminal_id.as_str() {
            // These terminals support `open -a <app> <path>` as folder handlers
            "terminal" => open_with_path("Terminal", None)?,
            "iterm2" => open_with_path("iTerm", Some("iTerm2"))?,

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Install the app bundle (brew install --cask kitty / wezterm / alacritty / iterm2)
  2. Switch the terminal selection in Settings to one that is installed
  3. Clear the stale terminal preference so the default is used

Example fix

# before: settings select 'Kitty' but only the CLI is installed
brew install kitty        # CLI only; `open -Ra Kitty` still fails

# after: install the app bundle
brew install --cask kitty
Defensive patterns

Strategy: validation

Validate before calling

fn app_installed(app: &str) -> bool {
    std::process::Command::new("open")
        .args(["-Ra", app])
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::null())
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

if !app_installed(&configured_terminal) {
    // fall back to Terminal.app or prompt the user before opening
}

Type guard

use but_error::{AnyhowContextExt, Code};

fn is_default_terminal_not_found(err: &anyhow::Error) -> bool {
    err.custom_context().is_some_and(|c| c.code == Code::DefaultTerminalNotFound)
}

Try / catch

match open_terminal(ctx, path).await {
    Err(err) if is_default_terminal_not_found(&err) => {
        // open settings / suggest installing the selected terminal app
    }
    other => other,
}

Prevention

When it happens

Trigger: The user selected a terminal (Kitty, WezTerm, Alacritty, iTerm...) whose app bundle is not installed, was installed under a different name, or was uninstalled after the setting was saved.

Common situations: Settings referencing an app the user removed; installing only a CLI (brew install kitty) without the application bundle; renamed app bundles after updates.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/2bed226d03b3eaeb. Report an issue: GitHub.