{"record":{"id":"3bcfcf2f7414a024","repo":"gitbutlerapp/gitbutler","slug":"cannot-unapply-anonymous-segments-yet-even-if-they","errorCode":null,"errorMessage":"Cannot unapply anonymous segments yet even if they have a stack id","messagePattern":"Cannot unapply anonymous segments yet even if they have a stack id","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/legacy/virtual_branches.rs","lineNumber":607,"sourceCode":"/// workspace: tip-most branch first, then branches closer to the workspace base.\nfn stack_branch_names(\n    ctx: &mut Context,\n    stack_id: StackId,\n    perm: &mut RepoExclusive,\n) -> Result<Vec<gix::refs::FullName>> {\n    let (_repo, ws, _) = ctx.workspace_mut_and_db_with_perm(perm)?;\n    let Some(stack) = ws.stacks.iter().find(|stack| stack.id == Some(stack_id)) else {\n        return Err(\n            anyhow!(\"branch with ID {stack_id} not found\").context(but_error::Code::BranchNotFound)\n        );\n    };\n\n    if stack\n        .segments\n        .first()\n        .is_none_or(|s| s.ref_name().is_none())\n    {\n        bail!(\"Cannot unapply anonymous segments yet even if they have a stack id\");\n    }\n\n    Ok(stack\n        .segments\n        .iter()\n        .filter_map(|segment| {\n            segment\n                .ref_info\n                .as_ref()\n                .map(|ref_info| ref_info.ref_name.clone())\n        })\n        .collect())\n}\n\n/// Commit assigned worktree changes so they remain with the branch being unapplied.\n///\n/// `ctx` supplies repository, workspace, metadata, and diff settings used to\n/// create the assignment commit. `branch` is the reference the new \"WIP","sourceCodeStart":589,"sourceCodeEnd":625,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/legacy/virtual_branches.rs#L589-L625","documentation":"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.","triggerScenarios":"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.","commonSituations":"Stacks produced by automation that skips branch naming; experimental/patch-style lanes; partially corrupted ref metadata after external git surgery.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const stacks = await client.branchList(projectId);\nconst stack = stacks.find((s) => s.id === stackId);\nif (!stack) throw new Error('stack not found');\nif (!stack.heads?.length) {\n  // anonymous segments have no named heads -> unapply unsupported\n  throw new Error('Stack has anonymous segments; name its branch before unapply');\n}\nawait client.unapplyStack(projectId, stackId);","typeGuard":"function isNamedStack(stack: { heads: Array<{ name: string }> | null }): boolean {\n  return (stack.heads?.length ?? 0) > 0;\n}","tryCatchPattern":"try {\n  await client.unapplyStack(projectId, stackId);\n} catch (e) {\n  if (String(e).includes('Cannot unapply anonymous segments')) {\n    // offer branch naming or stack deletion instead\n  } else throw e;\n}","preventionTips":["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"],"tags":["git","unapply","virtual-branches","anonymous-segments","rust"],"backgroundTag":"unsupported-anonymous-segment","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}