gitbutlerapp/gitbutler · critical

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` checks `repo.git_dir_trust()`; when gix reports the repository as not fully trusted (directory owned by a different user, like git's `safe.directory` protection), the project cannot be activated and this `RepoOwnership`-coded error is returned, telling the user to add the path to `safe.directory`. This mirrors git's own dubious-ownership safety mechanism to prevent privilege issues when a repo is owned by another account.

Solutions

  1. Run the suggested command: `git config --global --add safe.directory '<path shown in the error>'`.
  2. Or fix ownership: `sudo chown -R $(whoami) <repo path>`.
  3. In WSL, move the repo into the Linux filesystem (~/) or configure safe.directory as above.
  4. If in a container, run as the same UID as the mounted repo's owner or whitelist the path in safe.directory.

Example fix

// before
// RepoOwnership error when opening /home/alice/repo as bob
git config --global --add safe.directory '/home/alice/repo';
// or
sudo chown -R bob:bob /home/alice/repo
Defensive patterns

Strategy: validation

Validate before calling

# shell: check ownership before launching GitButler against a repo
stat -c '%U' "$REPO/.git"   # compare with current user
# or pre-add safe.directory:
git config --global --add safe.directory "$(realpath "$REPO")"

Try / catch

match prepare_project_for_activation(...) {
    Err(e) if e.to_string().contains("not owned by the current user") => {
        // surface the exact `git config --global --add safe.directory '<path>'` command to the user
        show_fix_hint(&e.to_string());
    }
    other => other?,
}

Prevention

When it happens

Trigger: Opening/activating a project whose `.git` (or workdir) is owned by a different OS user than the process running GitButler — e.g. repos under root-owned paths, WSL/Windows permission mismatches, containers mounting host repos, or shared network drives.

Common situations: Running the app as a different user than the one who cloned; Docker/container volumes; NFS/SMB shares; WSL accessing /mnt/c repos; repos copied with `sudo`.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/b4b778c712ac56be. Report an issue: GitHub.

Appendix: 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 58e5313667)