gitbutlerapp/gitbutler · error · anyhow::Error

configured storage path '{}' resolves to '.git' itself; choo

Error message

configured storage path '{}' resolves to '.git' itself; choose a dedicated GitButler directory instead

What it means

GitButler validates a configured in-git storage path (`storage_path_relative_to_git_dir`): its first component must be a normal directory name so storage resolves under `.git/<dir>`, never to `.git` itself. An empty or '.'-equivalent value would place the database and sentinel files directly inside the git dir and is refused.

Source

Thrown at crates/but-project-handle/src/storage_path.rs:91

    }

    let gitdir_real = gix::path::realpath(git_dir)?;
    Ok(storage_path
        .strip_prefix(&gitdir_real)
        .ok()
        .map(Path::to_owned))
}

/// Only accept `storage_path_relative_to_git_dir` if it's a top-level `gitbutler` directory.
/// Use `storage_path` to format error messages.
fn validate_in_git_storage_path(
    storage_path_relative_to_git_dir: &Path,
    storage_path: &Path,
) -> anyhow::Result<()> {
    let Some(Component::Normal(top_level_dir)) =
        storage_path_relative_to_git_dir.components().next()
    else {
        bail!(
            "configured storage path '{}' resolves to '.git' itself; choose a dedicated GitButler directory instead",
            storage_path.display()
        );
    };

    if !top_level_dir
        .to_string_lossy()
        .get(..DEFAULT_STORAGE_DIR_NAME.len())
        .is_some_and(|name| name.eq_ignore_ascii_case(DEFAULT_STORAGE_DIR_NAME))
    {
        bail!(
            "configured storage path '{}' resolves inside '.git' but not under a top-level 'gitbutler*' directory",
            storage_path.display()
        );
    }

    Ok(())
}

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Set the override to a dedicated top-level directory under .git, e.g. 'gitbutler'
  2. Remove the custom storage-path override entirely to fall back to the default 'gitbutler' directory
  3. If a custom name is wanted, use any top-level name starting with 'gitbutler' (case-insensitive)

Example fix

# before
storage_path_relative_to_git_dir = ""

# after
storage_path_relative_to_git_dir = "gitbutler"
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate the in-git storage path before saving the setting
use std::path::Component;
fn starts_with_normal_dir(rel: &std::path::Path) -> bool {
    matches!(rel.components().next(), Some(Component::Normal(_)))
}
if !starts_with_normal_dir(configured_rel) {
    return Err(anyhow::anyhow!("storage path must be a directory under .git, not .git itself"));
}

Try / catch

Catch the bail from settings save, show the configured value, and offer to reset the override to the default 'gitbutler' directory.

Prevention

When it happens

Trigger: Setting the storage path override to '.', an empty value, or any path whose first component is not a normal directory, so the resolved directory is the .git directory itself.

Common situations: Users trying to keep everything directly in .git by configuring '.'; a settings UI writing an empty string instead of unsetting the override; migrations that preserved an empty value.

Related errors


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