gitbutlerapp/gitbutler · error
`but setup` cannot run from a linked worktree; run it from…
Error message
`but setup` cannot run from a linked worktree; run it from the main worktree{} What it means
`but setup` (project initialization in `repo()`) discovers the repository with `gix::discover` and refuses to proceed when the discovered git dir differs from the common dir, i.e. the path is a linked worktree (`git worktree add`). GitButler project setup must run from the main worktree; the error appends the main worktree path when it can be resolved.
Solutions
- cd to the main worktree (path shown in the error message) and run `but setup` there
- Find the main worktree with `git worktree list` (the entry without a `worktree` annotation is main)
- Remove the linked worktree if unneeded (`git worktree remove <path>`) and set up from main
Example fix
// before cd ~/repo-feature-x # linked worktree but setup // after git worktree list cd ~/repo # main worktree but setup
Defensive patterns
Strategy: validation
Validate before calling
# only run setup from the main worktree
git_dir=$(git rev-parse --git-common-dir)
work_dir=$(git rev-parse --git-dir)
[ "$git_dir" = "$work_dir" ] || { echo "linked worktree; run from main"; exit 1; } Try / catch
match setup_result {
Err(e) if e.to_string().starts_with("`but setup` cannot run from a linked worktree") => {
// parse " at <path>" suffix and switch to main worktree
let main = parse_main_path(&e.to_string());
std::env::set_current_dir(main)?;
return setup_again();
}
other => other,
} Prevention
- Check `git rev-parse --git-dir` vs `--git-common-dir` before setup
- Use `git worktree list` to identify the main worktree
- Restrict `but setup` to bootstrap scripts that run in the primary checkout
- Avoid triggering setup from per-worktree automation
When it happens
Trigger: Running `but setup` while the current directory is a linked worktree created via `git worktree add`, pointing `-C` at a linked-worktree path, or scripting setup inside a per-worktree CI checkout.
Common situations: Developers using git worktrees for parallel branches who run setup from the wrong checkout; monorepo tooling that materializes linked worktrees; automation that picks the first directory found without checking it is the main worktree.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- The repository at is a non-main worktree. GitButler…
- Bare repositories are not supported.
- is a remote commit
- No git repository found at
- No git repository found - run `but setup --init` to…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/26b98f8a8787674e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/command/legacy/setup.rs:192
anyhow::bail!(
"No git repository found - run `but setup --init` to initialize a new repository."
);
}
}
}
}
// setup a gitbutler project for the repository at `repo_path`
pub(crate) fn repo(
ctx: &mut Context,
repo_path: &Path,
out: &mut OutputChannel,
perm: &mut RepoExclusive,
) -> anyhow::Result<()> {
let discovered = gix::discover(repo_path)?;
if discovered.git_dir() != discovered.common_dir() {
let main_worktree = discovered.main_repo()?;
anyhow::bail!(
"`but setup` cannot run from a linked worktree; run it from the main worktree{}",
main_worktree
.workdir()
.map(|dir| format!(" at {}", dir.display()))
.unwrap_or_default()
);
}
let t = theme::get();
let mut target_info: Option<TargetInfo> = None;
// what branch is head() pointing to?
let pre_head_name = {
let repo = ctx.repo.get()?;
let pre_head = repo.head()?;
pre_head
.referent_name()
.map(|n| n.shorten().to_string())
.unwrap_or_default()View on GitHub (pinned to 58e5313667)