{"record":{"id":"4c2850a4f6adb6bb","repo":"gitbutlerapp/gitbutler","slug":"cannot-unapply-non-existing-branch-branch","errorCode":null,"errorMessage":"Cannot unapply non-existing branch '{branch}'","messagePattern":"Cannot unapply non-existing branch '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/branch/unapply.rs","lineNumber":238,"sourceCode":"            );\n        }\n\n        if let Some(workspace_ref_name) = workspace_ref_name.as_ref()\n            && workspace_ref_name.as_ref() == branch\n        {\n            return unapply_workspace_reference(\n                ws,\n                repo,\n                meta,\n                workspace_ref_name.as_ref(),\n                workspace_disposition,\n            );\n        }\n\n        let branch_in_ws = ws.find_segment_and_stack_by_refname(branch);\n        if branch_in_ws.is_none() {\n            if branch_ref.is_none() {\n                bail!(\n                    \"Cannot unapply non-existing branch '{branch}'\",\n                    branch = branch.shorten()\n                );\n            }\n            // The branch exists in Git, but does not in the workspace: Nothing to do.\n            return Ok(Outcome::new(Cow::Borrowed(workspace)));\n        }\n        let branch_stack_was_entrypoint = branch_in_ws\n            .is_some_and(|(stack, _)| stack.segments.iter().any(|segment| segment.is_entrypoint));\n        let workspace_tip_was_entrypoint = ws.is_entrypoint();\n\n        let Some(workspace_ref_name) = workspace_ref_name else {\n            // This is an ad-hoc workspace by merit of being unnamed.\n            bail!(\"Cannot unapply a branch from an ad-hoc detached workspace\");\n        };\n        let mut ws_md = meta.workspace(workspace_ref_name.as_ref())?;\n        if ws.kind.has_managed_ref() || ws.has_metadata() {\n            ws.reconcile_metadata(&mut ws_md)?;","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-workspace/src/branch/unapply.rs#L220-L256","documentation":"unapply looks the branch up both in git (try_find_validated_ref) and in the workspace projection (find_segment_and_stack_by_refname). This error fires when both miss: the branch neither exists as a git reference nor as a segment in the workspace, so there is nothing to unapply and the name is simply wrong or stale.","triggerScenarios":"Calling unapply with a branch name that has no git ref and no workspace segment — typo, already-deleted branch, or a name that was never applied.","commonSituations":"Stale UI state after another client deleted the branch; scripts replaying an old branch list; short-name/full-name mismatches.","solutions":["Refresh the branch list (re-traverse workspace + repo refs) and only offer branches that still exist.","Treat this case as a no-op in idempotent callers instead of surfacing an error.","Verify the exact spelling and full ref name (refs/heads/...) before calling."],"exampleFix":"// before\nunapply(repo, meta, &ws, branch, opts)?;\n\n// after\nif repo.try_find_reference(branch)?.is_none()\n    && ws.find_segment_and_stack_by_refname(branch).is_none()\n{\n    return Ok(Outcome::new(Cow::Borrowed(&ws))); // nothing to unapply\n}\nunapply(repo, meta, &ws, branch, opts)?;","handlingStrategy":"validation","validationCode":"if repo.try_find_reference(branch)?.is_none()\n    && ws.find_segment_and_stack_by_refname(branch).is_none()\n{\n    // nothing to unapply: treat as idempotent no-op\n    return Ok(Outcome::new(Cow::Borrowed(&ws)));\n}","typeGuard":"fn branch_exists_anywhere(ws: &but_graph::Workspace, repo: &gix::Repository, branch: &FullNameRef) -> bool {\n    repo.try_find_reference(branch).ok().flatten().is_some()\n        || ws.find_segment_and_stack_by_refname(branch).is_some()\n}","tryCatchPattern":"match unapply(repo, meta, &ws, branch, opts) {\n    Err(err) if err.to_string().contains(\"non-existing branch\") => {\n        Ok(Outcome::new(Cow::Borrowed(&ws))) // idempotent no-op\n    }\n    other => other,\n}","preventionTips":["Refresh branch lists before offering unapply actions.","Make batch unapply idempotent: treat missing branches as done.","Validate exact full ref names from user input."],"tags":["gitbutler","unapply","branch-not-found","rust"],"backgroundTag":"branch-not-found","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}