gitbutlerapp/gitbutler · error · anyhow::Error
Cannot unapply anonymous segments yet even if they have a st
Error message
Cannot unapply anonymous segments yet even if they have a stack id
What it means
stack_branch_names, used while unapplying a stack (crates/but-api/src/legacy/virtual_branches.rs:590-620), bails when the stack's first segment has no ref name: an 'anonymous' segment created without a branch ref. Unapply only knows how to remove named segments, so anonymous stacks are explicitly not yet supported even though they carry a stack id.
Source
Thrown at crates/but-api/src/legacy/virtual_branches.rs:607
/// workspace: tip-most branch first, then branches closer to the workspace base.
fn stack_branch_names(
ctx: &mut Context,
stack_id: StackId,
perm: &mut RepoExclusive,
) -> Result<Vec<gix::refs::FullName>> {
let (_repo, ws, _) = ctx.workspace_mut_and_db_with_perm(perm)?;
let Some(stack) = ws.stacks.iter().find(|stack| stack.id == Some(stack_id)) else {
return Err(
anyhow!("branch with ID {stack_id} not found").context(but_error::Code::BranchNotFound)
);
};
if stack
.segments
.first()
.is_none_or(|s| s.ref_name().is_none())
{
bail!("Cannot unapply anonymous segments yet even if they have a stack id");
}
Ok(stack
.segments
.iter()
.filter_map(|segment| {
segment
.ref_info
.as_ref()
.map(|ref_info| ref_info.ref_name.clone())
})
.collect())
}
/// Commit assigned worktree changes so they remain with the branch being unapplied.
///
/// `ctx` supplies repository, workspace, metadata, and diff settings used to
/// create the assignment commit. `branch` is the reference the new "WIPView on GitHub (pinned to caf1f223d3)
Solutions
- Give the stack's segment a branch name (create/name the branch in the UI or via branchCreate) and retry unapply
- Use a different end action for anonymous stacks, e.g. delete the stack, until anonymous unapply ships
- If the stack should have been named, inspect workspace metadata for lost ref_info and restore the branch reference
Defensive patterns
Strategy: validation
Validate before calling
const stacks = await client.branchList(projectId);
const stack = stacks.find((s) => s.id === stackId);
if (!stack) throw new Error('stack not found');
if (!stack.heads?.length) {
// anonymous segments have no named heads -> unapply unsupported
throw new Error('Stack has anonymous segments; name its branch before unapply');
}
await client.unapplyStack(projectId, stackId); Type guard
function isNamedStack(stack: { heads: Array<{ name: string }> | null }): boolean {
return (stack.heads?.length ?? 0) > 0;
} Try / catch
try {
await client.unapplyStack(projectId, stackId);
} catch (e) {
if (String(e).includes('Cannot unapply anonymous segments')) {
// offer branch naming or stack deletion instead
} else throw e;
} Prevention
- Create stacks with a branch name so unapply always works
- Check the stack's heads/segments are named before showing the unapply action
- For anonymous lanes, steer users to delete-stack instead of unapply
When it happens
Trigger: Calling unapplyStack(projectId, stackId) on a stack whose segments were created without branch names (anonymous lane/patch stack), or whose head segment lost its ref_info in workspace metadata.
Common situations: Stacks produced by automation that skips branch naming; experimental/patch-style lanes; partially corrupted ref metadata after external git surgery.
Related errors
- Failed to unapply branch due to conflicts while rebuilding t
- No uncommitted changes assigned to branch: {branch_name}
- Unable to determine target commit for unassigned change: {}
- Ad-hoc (single-branch) branch moves are not supported inside
- Failed to communicate with LM Studio server: ${error instanc
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/3bcfcf2f7414a024.
Report an issue: GitHub.