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 "WIP

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Give the stack's segment a branch name (create/name the branch in the UI or via branchCreate) and retry unapply
  2. Use a different end action for anonymous stacks, e.g. delete the stack, until anonymous unapply ships
  3. 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

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


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/3bcfcf2f7414a024. Report an issue: GitHub.