gitbutlerapp/gitbutler · error

Installation path {} is a file, not a directory. Please spec

Error message

Installation path {} is a file, not a directory. Please specify a directory path.

What it means

Before writing skill files into a destination, `but skill install` validates that the path can hold a directory tree. If install_path exists and is a regular file (is_file()), creating SKILL.md and references/ under it is impossible, so the command fails with the offending path instead of attempting partial writes.

Source

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

    } else {
        None
    };
    let installed_for_driving_agent = agent_default_path.is_some();
    let install_paths = if let Some(custom) = custom_path {
        vec![resolve_custom_path(&custom, ctx, global)?]
    } else if detect {
        detect_install_paths(ctx, global)?
    } else if let Some(path) = agent_default_path {
        vec![path]
    } else {
        vec![prompt_for_install_path(ctx, global, out, &mut progress)?]
    };

    let mut version = "";
    for install_path in &install_paths {
        // Validate installation path
        if install_path.exists() && install_path.is_file() {
            anyhow::bail!(
                "Installation path {} is a file, not a directory. Please specify a directory path.",
                install_path.display()
            );
        }

        // Check if files already exist and warn user
        if install_path.join("SKILL.md").exists()
            && let Some(writer) = out.for_human()
        {
            writeln!(writer)?;
            writeln!(
                writer,
                "{} Skill files already exist at {}",
                t.sym().warning,
                t.config_value.paint(install_path.display().to_string())
            )?;
            writeln!(writer, "  Overwriting existing files...")?;
            writeln!(writer)?;

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Point --path at a directory path that is free or already a directory
  2. Move or delete the conflicting file: `mv ~/.claude/skills ~/.claude/skills.bak`
  3. If the path is a symlink, retarget it to a directory

Example fix

$ ls -l ~/.claude/skills    # regular file -> fails
$ rm ~/.claude/skills
$ but skill install --path ~/.claude/skills
Defensive patterns

Strategy: validation

Validate before calling

match std::fs::metadata(&path) {
    Ok(m) if m.is_file() => { /* pick another path or stop before invoking */ }
    Ok(m) if m.is_dir() => { /* safe */ }
    _ => { /* path free: also safe */ }
}

Prevention

When it happens

Trigger: Passing --path that resolves to an existing regular file - a leftover marker file named like the target directory, or a symlink pointing at a file rather than a directory.

Common situations: Dotfile layouts where ~/.claude/skills is a file, leftovers from earlier tooling, typos in --path colliding with an existing file name.

Related errors


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