{"record":{"id":"d598ef8d87900f73","repo":"gitbutlerapp/gitbutler","slug":"cannot-reconcile-source-branch-name-name-oc","errorCode":null,"errorMessage":"Cannot reconcile {source}: branch name '{name}' occurs more than once","messagePattern":"Cannot reconcile (.+?): branch name '(.+?)' occurs more than once","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-core/src/ref_metadata.rs","lineNumber":533,"sourceCode":"    config: &mut gix::config::File,\n    key: &str,\n    value: Option<impl AsRef<str>>,\n) -> anyhow::Result<()> {\n    match value {\n        Some(value) => git_config::set_config_value(config, key, value.as_ref())?,\n        None => git_config::remove_config_value(config, key)?,\n    }\n    Ok(())\n}\n\nfn ensure_unique_branch_names<'a>(\n    names: impl IntoIterator<Item = &'a gix::refs::FullNameRef>,\n    source: &str,\n) -> Result<()> {\n    let mut seen = Vec::<gix::refs::FullName>::new();\n    for name in names {\n        if seen.iter().any(|seen| seen.as_ref() == name) {\n            bail!(\"Cannot reconcile {source}: branch name '{name}' occurs more than once\");\n        }\n        seen.push(name.to_owned());\n    }\n    Ok(())\n}\n\nfn remove_branch_from_stacks(\n    stacks: &mut [WorkspaceStack],\n    preferred_stack_idx: usize,\n    name: &gix::refs::FullNameRef,\n) -> Option<WorkspaceStackBranch> {\n    if let Some(stack) = stacks.get_mut(preferred_stack_idx)\n        && let Some(branch_idx) = stack\n            .branches\n            .iter()\n            .position(|branch| branch.ref_name.as_ref() == name)\n    {\n        return Some(stack.branches.remove(branch_idx));","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-core/src/ref_metadata.rs#L515-L551","documentation":"During metadata reconciliation, `ensure_unique_branch_names()` walks all workspace branch refs and rejects the operation if the same full ref name (`refs/heads/...`) appears twice. Duplicate workspace branches would make stack/branch reconciliation ambiguous, so it refuses rather than guessing. The `source` string names which reconciliation step failed.","triggerScenarios":"Calling the reconcile path when two stacks (or two segments) in the workspace metadata reference the same full branch ref — typically after a sync bug duplicated a stack, metadata was restored from a backup on top of existing state, or branches were merged between stacks manually.","commonSituations":"Two GitButler clients writing concurrently before locking was airtight; copying project data directories between machines; recovering `metadata.toml`/database from a snapshot while refs also exist in git; importing the same branch into two stacks.","solutions":["List the workspace stacks and find the duplicated ref name (the error names it), then delete or rename one of the stacks/branches so each full ref occurs once.","Rename the duplicate branch in one stack before reconciling.","If both copies are stale, remove the redundant stack via GitButler UI/CLI and retry the operation that triggered reconciliation.","Report to GitButler if the duplication arose without manual recovery steps — the writer allowed an invalid state."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Rust — detect duplicates before triggering reconciliation\nfn find_duplicate_branch_names<'a>(\n    names: impl IntoIterator<Item = &'a gix::refs::FullNameRef>,\n) -> Option<String> {\n    let mut seen = std::collections::HashSet::new();\n    for name in names {\n        if !seen.insert(name.as_bstr().to_owned()) {\n            return Some(name.to_string());\n        }\n    }\n    None\n}","typeGuard":null,"tryCatchPattern":"if let Some(dup) = find_duplicate_branch_names(all_refs) {\n    // offer the user a rename/remove of one duplicate before reconciling\n    return prompt_resolve_duplicate(dup);\n}\nreconcile(all_refs)?;","preventionTips":["Refuse to attach a branch ref to a second stack at write time so duplicates can't form.","Don't restore metadata backups on top of live state; wipe or merge deliberately.","After any manual metadata surgery, run a uniqueness check over workspace branch refs."],"tags":["branch-names","duplicate","ref-metadata","reconciliation"],"backgroundTag":"duplicate-branch-name","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}