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
- Run the command from the message as the user running GitButler: git config --global --add safe.directory '<path>'
- Alternatively fix the root cause: sudo chown -R $(id -u):$(id -g) <repo-path>
- 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
- Clone repos as the user that runs GitButler
- After restoring or copying repos, chown them to the working user
- Check git_dir_trust before registering a project path
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
- No push remote set or more than one remote
- No uncommitted changes found for the selected files
- Failed to determine target commit for hunk absorption due to
- Stack has no branches
- Failed to create blank commit in stack: {stack_id:?}
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/b4b778c712ac56be.
Report an issue: GitHub.