gitbutlerapp/gitbutler · error · but_error::Code

RepoOwnership

RepoOwnership

Error message

The git directory is considered unsafe as it's not owned by the current user. Use `git config --global --add safe.directory '{}'` to allow it

What it means

assure_repo_ownership() mirrors git's 'dubious ownership' protection using gix: if the repository's git dir is not fully trusted (owned by a user other than the current one), project operations abort with Code::RepoOwnership and the message includes the exact safe.directory command to run.

Source

Thrown at crates/but-api/src/legacy/projects.rs:194

/// Prepare an already-known project for activation in the UI or server.
///
/// This repairs missing target metadata in freshly selected storage locations.
pub fn prepare_project_for_activation(ctx: &mut Context) -> Result<()> {
    assure_repo_ownership(&*ctx.repo.get()?)?;
    let _guard = ctx.exclusive_worktree_access();
    gitbutler_branch_actions::base::bootstrap_default_target_if_missing(ctx)?;
    Ok(())
}

// TODO(gix): remove this once there is no `git2` as `gix` provides safety by not trusting Git configuration instead.
fn assure_repo_ownership(repo: &gix::Repository) -> Result<()> {
    if repo.git_dir_trust() == gix::sec::Trust::Full {
        return Ok(());
    }

    let path = repo.workdir().unwrap_or(repo.git_dir());
    Err(anyhow!(
        "The git directory is considered unsafe as it's not owned by the current user. Use `git config --global --add safe.directory '{}'` to allow it",
        path.display()
    )
    .context(Code::RepoOwnership))
}

#[but_api]
#[instrument(err(Debug))]
pub fn is_gerrit(ctx: &but_ctx::Context) -> Result<bool> {
    let repo = ctx.repo.get()?;
    Ok(
        gitbutler_project::gerrit::is_used_by_default_remote(&repo).unwrap_or_else(|err| {
            tracing::debug!(?err, "Gerrit detection failed");
            false
        }),
    )
}

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Run the command from the message as the user running GitButler: git config --global --add safe.directory '<path>'
  2. Alternatively fix the root cause: sudo chown -R $(id -u):$(id -g) <repo-path>
  3. Reopen or re-add the project in GitButler

Example fix

# before: project fails to open with Code::RepoOwnership

# after (as the user running GitButler)
git config --global --add safe.directory /home/user/projects/my-repo
# or fix the root cause:
sudo chown -R $(id -u):$(id -g) /home/user/projects/my-repo
Defensive patterns

Strategy: validation

Validate before calling

fn repo_is_trusted(repo: &gix::Repository) -> bool {
    repo.git_dir_trust() == gix::sec::Trust::Full
}

// before adding/opening the project:
if !repo_is_trusted(&repo) {
    // show safe.directory/chown guidance instead of failing later
}

Type guard

use but_error::{AnyhowContextExt, Code};

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

Try / catch

match open_project(ctx, id) {
    Err(err) if is_repo_ownership_error(&err) => {
        // show the safe.directory command from the message and let the user fix ownership
    }
    other => other,
}

Prevention

When it happens

Trigger: Adding or opening a project whose .git directory is owned by another uid: cloned with sudo, created inside a container or volume mount, copied from another user, or living on a filesystem with unexpected ownership.

Common situations: Docker/VM shared-folder checkouts; repos set up by an admin; home directories copied between users; CI running as a different user than the checkout owner.

Related errors


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