gitbutlerapp/gitbutler · error · anyhow::Error
Worktree {name} has no usable HEAD
Error message
Worktree {name} has no usable HEAD What it means
Thrown by active_worktree() in but-api when a named worktree exists and is not archived, but ctx.worktree_head() resolves to None, meaning HEAD cannot be turned into a usable commit. The source comment lists the accepted causes: an unborn branch, a checkout of the GitButler workspace ref, or a broken HEAD. The library refuses to continue because the caller needs a real commit to build a ChangeSource for an editor-backed operation.
Source
Thrown at crates/but-api/src/worktrees.rs:72
/// Look up the *active* linked worktree named `name`.
///
/// Every command here operates on active worktrees only - an archived one is
/// hidden from the graph, so operations against it could not be materialized.
///
/// Must not be called while a database handle is borrowed, see
/// [`but_ctx::Context::worktrees_with_state()`].
fn active_worktree(ctx: &but_ctx::Context, name: &str) -> Result<WorktreeEntry> {
let worktree = ctx
.worktrees_with_state()?
.into_iter()
.find(|worktree| worktree.name == name.as_bytes())
.with_context(|| format!("Worktree {name} does not exist"))?;
if worktree.archived {
bail!("Worktree {name} is archived");
}
if ctx.worktree_head(worktree.name.as_bstr())?.is_none() {
// Unborn, workspace-ref checkout, or broken - nothing to operate on.
bail!("Worktree {name} has no usable HEAD");
}
Ok(worktree)
}
/// Open the checkout that `source` reads its changes from, returning its stable
/// name along with a plain from-disk open of it, or `None` for the main worktree.
///
/// Callers turn this into a [`ChangeSource`](but_workspace::commit::ChangeSource)
/// for the duration of an editor-backed operation.
///
/// Must not be called while a database handle is borrowed, see
/// [`but_ctx::Context::worktrees_with_state()`].
pub(crate) fn open_changes_source(
ctx: &but_ctx::Context,
source: &ChangesSource,
) -> Result<Option<(BString, gix::Repository)>> {
let ChangesSource::Worktree(name) = source else {
return Ok(None);View on GitHub (pinned to caf1f223d3)
Solutions
- Make the first commit on the worktree's branch, or re-checkout an existing branch, so HEAD points at a real commit
- If HEAD targets the GitButler workspace ref, switch that worktree to a normal branch before running the operation
- Inspect the worktree's HEAD (in .git/worktrees/<name>/HEAD) for corruption; repair with git symbolic-ref or git checkout
- Choose a different, initialized worktree for the operation
Example fix
# before: worktree on a brand-new branch, HEAD is unborn git worktree add ../wt -b brand-new git -C ../wt log # fails: does not have any commits yet # after: give HEAD a commit (or base the worktree on an existing branch) git -C ../wt commit --allow-empty -m 'init' # now active_worktree() finds a usable HEAD
Defensive patterns
Strategy: validation
Validate before calling
// Rust: resolve HEAD yourself before any editor-backed worktree operation
let wt = ctx.worktrees_with_state()?.into_iter()
.find(|w| w.name == name.as_bytes())
.with_context(|| format!("worktree {name} missing"))?
.clone();
if !wt.archived && ctx.worktree_head(wt.name.as_bstr())?.is_none() {
// unborn / workspace-ref / broken HEAD — skip or prompt, don't call the API
return Ok(WorktreeReadiness::NeedsInit);
} Try / catch
// treat as a user-facing readiness problem, not a crash
match active_worktree(&ctx, name) {
Err(e) if e.to_string().contains("no usable HEAD") => prompt_init_first(&name),
r => r?,
} Prevention
- Create the first commit immediately when adding a worktree on a new branch
- Avoid checking worktrees out onto the GitButler workspace ref when you plan editor-backed operations
- Surface worktree readiness (HEAD resolvable) in the UI before enabling actions that need it
When it happens
Trigger: Any but-api operation that funnels through active_worktree(ctx, name) (opening a change source / editor operation on a worktree) when the worktree's HEAD is unborn (fresh 'git worktree add -b new-branch' with no commits yet), points at the GitButler workspace ref instead of a branch, or its HEAD file/ref is corrupt so worktree_head() returns None.
Common situations: A just-created worktree on a brand-new branch (git prints 'branch is unborn'); GitButler-managed worktrees checked out to the workspace ref; a repo copied or synced with a damaged .git/HEAD or a detached-but-missing target ref.
Related errors
- Invalid token format
- HTTP Error ${response.statusText}: ${text}
- Not currently on a gitbutler/* branch.
- Bare repositories are not supported.
- Cannot currently work in repositories without a worktree
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/451250bb3b2610a7.
Report an issue: GitHub.