gitbutlerapp/gitbutler · error

The repository at {} is a non-main worktree. GitButler requi

Error message

The repository at {} is a non-main worktree. GitButler requires the main worktree.

What it means

Raised while registering a repository: the path is a git worktree, but a linked (non-main) one — `AddProjectOutcome::NonMainWorktree`. These are created with `git worktree add` and share the object database with the main worktree; GitButler only supports operating on the main worktree.

Source

Thrown at crates/but/src/command/legacy/setup.rs:246

                    "  {}",
                    t.success.paint("✓ Repository already in project registry")
                )?;
            }
            Ok(ProjectStatus::AlreadyExists)
        }
        gitbutler_project::AddProjectOutcome::PathNotFound => Err(anyhow::anyhow!(
            "The path {} does not exist",
            repo_path.display()
        )),
        gitbutler_project::AddProjectOutcome::NotADirectory => Err(anyhow::anyhow!(
            "The path {} is not a directory",
            repo_path.display()
        )),
        gitbutler_project::AddProjectOutcome::BareRepository => Err(anyhow::anyhow!(
            "The repository at {} is bare. GitButler requires a non-bare repository.",
            repo_path.display()
        )),
        gitbutler_project::AddProjectOutcome::NonMainWorktree => Err(anyhow::anyhow!(
            "The repository at {} is a non-main worktree. GitButler requires the main worktree.",
            repo_path.display()
        )),
        gitbutler_project::AddProjectOutcome::NoWorkdir => Err(anyhow::anyhow!(
            "The repository at {} has no working directory. GitButler requires a working directory.",
            repo_path.display()
        )),
        gitbutler_project::AddProjectOutcome::NoDotGitDirectory => Err(anyhow::anyhow!(
            "The repository at {} has no .git directory. GitButler requires a .git directory.",
            repo_path.display()
        )),
        gitbutler_project::AddProjectOutcome::ReftableRefFormatUnsupported => Err(anyhow::anyhow!(
            "The repository at {} uses the currently unsupported reftable reference format.",
            repo_path.display()
        )),
        gitbutler_project::AddProjectOutcome::NotAGitRepository(_) => Err(anyhow::anyhow!(
            "The path {} is not a git repository.",
            repo_path.display()

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Run setup in the main worktree of the clone (where the real `.git` directory lives)
  2. Find the main worktree from the linked one: `git -C /the/path rev-parse --git-common-dir` strips the trailing path — or check `git worktree list`
  3. If you need isolation, clone the repository again instead of using a linked worktree

Example fix

# before: linked worktree created by 'git worktree add'
but setup ~/hotfix-worktree

# after: main worktree of the same clone
git -C ~/hotfix-worktree worktree list   # locate the main checkout
but setup ~/repos/project               # the main worktree
Defensive patterns

Strategy: validation

Validate before calling

let output = std::process::Command::new("git")
    .args(["-C", repo_path.to_str().unwrap(), "rev-parse", "--git-path", ".."])
    .output()?;
// simpler: compare git-dir and git-common-dir
let git_dir = std::process::Command::new("git").args(["-C", path, "rev-parse", "--git-dir"]).output()?;
let common_dir = std::process::Command::new("git").args(["-C", path, "rev-parse", "--git-common-dir"]).output()?;
if git_dir.stdout != common_dir.stdout {
    anyhow::bail!("linked worktree; register the main worktree instead");
}

Type guard

fn is_non_main_worktree(out: &gitbutler_project::AddProjectOutcome) -> bool {
    matches!(out, gitbutler_project::AddProjectOutcome::NonMainWorktree)
}

Try / catch

match add_project(&repo_path) {
    Ok(out) if is_non_main_worktree(&out) => { /* locate main worktree via 'git worktree list' */ }
    Ok(out) => { /* other outcomes */ }
    Err(err) if err.to_string().contains("non-main worktree") => { /* worktree guidance */ }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Running setup inside a directory created by `git worktree add ../hotfix` (its `.git` is a file pointing back at the main repo's worktrees area), rather than in the original clone.

Common situations: Developers using linked worktrees for parallel branches; CI agents reusing a worktree checkout; opening a worktree directory from a recent-files list.

Related errors


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