{"record":{"id":"451250bb3b2610a7","repo":"gitbutlerapp/gitbutler","slug":"worktree-name-has-no-usable-head","errorCode":null,"errorMessage":"Worktree {name} has no usable HEAD","messagePattern":"Worktree (.+?) has no usable HEAD","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/worktrees.rs","lineNumber":72,"sourceCode":"/// Look up the *active* linked worktree named `name`.\n///\n/// Every command here operates on active worktrees only - an archived one is\n/// hidden from the graph, so operations against it could not be materialized.\n///\n/// Must not be called while a database handle is borrowed, see\n/// [`but_ctx::Context::worktrees_with_state()`].\nfn active_worktree(ctx: &but_ctx::Context, name: &str) -> Result<WorktreeEntry> {\n    let worktree = ctx\n        .worktrees_with_state()?\n        .into_iter()\n        .find(|worktree| worktree.name == name.as_bytes())\n        .with_context(|| format!(\"Worktree {name} does not exist\"))?;\n    if worktree.archived {\n        bail!(\"Worktree {name} is archived\");\n    }\n    if ctx.worktree_head(worktree.name.as_bstr())?.is_none() {\n        // Unborn, workspace-ref checkout, or broken - nothing to operate on.\n        bail!(\"Worktree {name} has no usable HEAD\");\n    }\n    Ok(worktree)\n}\n\n/// Open the checkout that `source` reads its changes from, returning its stable\n/// name along with a plain from-disk open of it, or `None` for the main worktree.\n///\n/// Callers turn this into a [`ChangeSource`](but_workspace::commit::ChangeSource)\n/// for the duration of an editor-backed operation.\n///\n/// Must not be called while a database handle is borrowed, see\n/// [`but_ctx::Context::worktrees_with_state()`].\npub(crate) fn open_changes_source(\n    ctx: &but_ctx::Context,\n    source: &ChangesSource,\n) -> Result<Option<(BString, gix::Repository)>> {\n    let ChangesSource::Worktree(name) = source else {\n        return Ok(None);","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/worktrees.rs#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: worktree on a brand-new branch, HEAD is unborn\ngit worktree add ../wt -b brand-new\ngit -C ../wt log   # fails: does not have any commits yet\n\n# after: give HEAD a commit (or base the worktree on an existing branch)\ngit -C ../wt commit --allow-empty -m 'init'\n# now active_worktree() finds a usable HEAD","handlingStrategy":"validation","validationCode":"// Rust: resolve HEAD yourself before any editor-backed worktree operation\nlet wt = ctx.worktrees_with_state()?.into_iter()\n    .find(|w| w.name == name.as_bytes())\n    .with_context(|| format!(\"worktree {name} missing\"))?\n    .clone();\nif !wt.archived && ctx.worktree_head(wt.name.as_bstr())?.is_none() {\n    // unborn / workspace-ref / broken HEAD — skip or prompt, don't call the API\n    return Ok(WorktreeReadiness::NeedsInit);\n}","typeGuard":null,"tryCatchPattern":"// treat as a user-facing readiness problem, not a crash\nmatch active_worktree(&ctx, name) {\n    Err(e) if e.to_string().contains(\"no usable HEAD\") => prompt_init_first(&name),\n    r => r?,\n}","preventionTips":["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"],"tags":["worktree","git","head","unborn-branch","but-api"],"backgroundTag":"unborn-git-branch","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}