gitbutlerapp/gitbutler · error · anyhow::Error
Worktree {name} has a workspace ref checked out, so there is
Error message
Worktree {name} has a workspace ref checked out, so there is no branch to commit to What it means
worktree_branch() resolves which branch a worktree's HEAD is on before an operation may commit to it. Besides detached HEAD, it explicitly refuses GitButler workspace refs (but_core::is_workspace_ref_name): such worktrees render without a heading but their HEAD points at internal workspace state, and a commit meant for a branch must never land on the workspace ref. The checkout can change between TUI render and confirm, so this is re-checked at confirm time.
Source
Thrown at crates/but/src/utils/worktrees.rs:19
use anyhow::Context as _;
use bstr::BStr;
/// The branch checked out in the linked worktree `name`, which is where a commit made from that
/// checkout goes and where a commit moved onto its lane lands.
///
/// A detached worktree has no branch to move, so it is refused rather than silently targeting
/// somewhere else. The same goes for a workspace ref: such worktrees never render a heading,
/// but the checkout can change between render and confirm, and a workspace ref must never
/// receive a commit meant for a branch.
pub(crate) fn worktree_branch(
repo: &gix::Repository,
name: &BStr,
) -> anyhow::Result<gix::refs::FullName> {
let worktree_repo = but_workspace::worktrees::open_worktree_repo(repo, name)?;
let branch = worktree_repo.head_name()?.with_context(|| {
format!("Worktree {name} has a detached HEAD, so there is no branch to commit to")
})?;
anyhow::ensure!(
!but_core::is_workspace_ref_name(branch.as_ref()),
"Worktree {name} has a workspace ref checked out, so there is no branch to commit to"
);
Ok(branch)
}
View on GitHub (pinned to caf1f223d3)
Solutions
- Refresh/re-render the TUI, reselect the target, and confirm again
- In the affected worktree, put HEAD back on a real branch: `git switch <branch>`
- Run only one GitButler surface (app or CLI) per repository at a time
Defensive patterns
Strategy: validation
Validate before calling
let head = worktree_repo.head_name()?;
match head {
Some(name) if !but_core::is_workspace_ref_name(name.as_ref()) => Ok(name),
Some(_) => anyhow::bail!("workspace ref checked out; reselect after refresh"),
None => anyhow::bail!("detached HEAD; no branch"),
} Try / catch
On this error, re-read the worktree's HEAD and restart from a fresh render; never retry the commit against the workspace-ref state.
Prevention
- Re-validate HEAD at confirm time, not only at render time
- One writer per repository: avoid concurrent app and CLI mutations
When it happens
Trigger: Confirming an operation that targets a worktree (commit, branch move) after that worktree's HEAD was switched to a GitButler workspace ref, by a re-render in the TUI or by another but/GitButler process touching the worktree concurrently.
Common situations: Race between TUI render and confirmation; running the but CLI/TUI and the GitButler desktop app against the same repository at the same time.
Related errors
- Worktree {name} has no usable HEAD
- Could not discard all selected changes: {refused_paths}
- When using OpenAI in a bring your own key configuration, you
- Invalid token format
- Login token expired. Please log in to GitButler again.
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/b6bfa74d4b9f934c.
Report an issue: GitHub.