gitbutlerapp/gitbutler · error

Could not detect an existing GitButler skill installation. R

Error message

Could not detect an existing GitButler skill installation.
Run `but skill install` to create one, or use `--path <dir>` to choose a location.

What it means

detect_install_paths backs the --detect flag of `but skill update`/`but skill status`: it collects installation paths from the local (repo) scope and the global scope, in that priority. If neither scope contains a GitButler skill installation, there is nothing to detect or update and the command bails with instructions to install or pass --path.

Source

Thrown at crates/but/src/command/skill/mod.rs:832

/// Returns every GitButler skill in the highest-priority scope that has one
/// (local before global), so `--detect` refreshes them all instead of forcing a
/// choice between them. Filtering to a single scope keeps a repo-local `--detect`
/// from reaching into global installs.
fn detect_install_paths(ctx: Option<&mut Context>, global: bool) -> Result<Vec<PathBuf>> {
    let installations = find_all_installations(ctx, true, !global)?;

    for scope in [SCOPE_LOCAL, SCOPE_GLOBAL] {
        let paths: Vec<PathBuf> = installations
            .iter()
            .filter(|(_, _, s)| *s == scope)
            .map(|(path, _, _)| path.clone())
            .collect();
        if !paths.is_empty() {
            return Ok(paths);
        }
    }

    anyhow::bail!(
        "Could not detect an existing GitButler skill installation.\n\
         Run `but skill install` to create one, or use `--path <dir>` to choose a location."
    )
}

fn prompt_for_install_scope(
    input: &mut crate::utils::InputOutputChannel<'_>,
    progress: &mut impl std::io::Write,
) -> Result<InstallScope> {
    let t = theme::get();
    writeln!(progress)?;
    writeln!(
        progress,
        "{}",
        t.important.paint("Select installation scope:")
    )?;
    writeln!(progress)?;

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Run `but skill install` to create an installation first, then retry --detect
  2. Pass `--path <dir>` pointing at the existing moved/renamed installation
  3. Reinstall at the default location so future `--detect` updates work

Example fix

$ but skill update --detect   # fails: nothing installed
$ but skill install            # create one
$ but skill update --detect    # now succeeds
Defensive patterns

Strategy: validation

Validate before calling

// verify an installation exists before `update --detect`
let installed = [".claude/skills/gitbutler", /* global path */]
    .iter()
    .any(|p| std::path::Path::new(p).join("SKILL.md").exists());
if !installed { /* run `but skill install` instead of `update --detect` */ }

Prevention

When it happens

Trigger: Calling `but skill update --detect` before `but skill install` was ever run, or after the skill directory (e.g. .claude/skills/gitbutler or the global equivalent) was deleted or moved to a non-default location.

Common situations: Fresh machine where the skill was never installed, cleanup scripts that wiped dotfile directories, installations renamed so detection scans miss them.

Related errors


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