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
- Run the suggested command: `git config --global --add safe.directory '<path shown in the error>'`.
- Or fix ownership: `sudo chown -R $(whoami) <repo path>`.
- In WSL, move the repo into the Linux filesystem (~/) or configure safe.directory as above.
- 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
- Own the repo with the same user that runs the tool (chown after sudo operations)
- Avoid working on host-mounted/network-share repos across user boundaries
- In WSL, keep repos in the Linux filesystem; whitelist cross-ownership paths in safe.directory
- Run containers as the same UID as the mounted repo's owner
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
- Path to read from at
- Refusing to read Git-ignored path
- Refusing to read Git metadata path
- Refusing to read ' ' from commit as it's not relative to…
- Aborting due to empty branch name
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)