{"record":{"id":"10fa60ad00f8beac","repo":"gitbutlerapp/gitbutler","slug":"tearing-off-a-branch-requires-a-workspace-common-b","errorCode":null,"errorMessage":"Tearing off a branch requires a workspace common base","messagePattern":"Tearing off a branch requires a workspace common base","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/branch/move_branch.rs","lineNumber":111,"sourceCode":"                ws_meta,\n                new_tip: None,\n                branch_stack_order: None,\n            });\n        }\n\n        let Some(workspace_head) = workspace.tip_commit().map(|commit| commit.id) else {\n            bail!(\"Couldn't find workspace head.\")\n        };\n        let head_selector = editor\n            .select_commit(workspace_head)\n            .context(\"Failed to find the workspace head in the graph.\")?;\n\n        let Some(lower_bound_ref) = workspace\n            .lower_bound_segment_id\n            .map(|segment_id| &workspace.graph[segment_id])\n            .and_then(|segment| segment.ref_name())\n        else {\n            bail!(\"Tearing off a branch requires a workspace common base\");\n        };\n\n        let target_selector = editor\n            .select_reference(lower_bound_ref)\n            .context(\"Failed to find target reference in graph.\")?;\n\n        let DisconnectParameters {\n            delimiter: subject_delimiter,\n            children_to_disconnect,\n            parents_to_disconnect,\n        } = get_disconnect_parameters(\n            &editor,\n            source_stack,\n            subject_segment,\n            Some(workspace_head),\n        )?;\n\n        editor.disconnect_segment_from(","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-workspace/src/branch/move_branch.rs#L93-L129","documentation":"Thrown by the tear-off path of move_branch in a managed workspace when the workspace has no lower-bound segment carrying a ref name. The lower bound ref (the workspace's common base/target branch) is what the torn-off branch gets re-parented onto, so without it the disconnect operation has no anchor target to select in the graph. It signals a workspace whose base stack is anonymous or missing rather than a bad API call.","triggerScenarios":"Calling move_branch's tear-off flow when workspace.lower_bound_segment_id is None, or when the segment at that index has no ref_name() (an anonymous base segment). This happens for workspaces built on detached-HEAD bases or local-only commits with no target branch ref.","commonSituations":"Workspace created while HEAD was detached or on commits with no base branch; workspace whose target ref was deleted or never synced; repositories where the user never picked a target branch in GitButler settings.","solutions":["Set (or restore) a target/base branch for the workspace in GitButler settings and re-sync, so the workspace has a named lower bound segment.","Verify workspace.lower_bound_segment_id maps to a segment whose ref_name() is Some(...) before invoking the tear-off move.","If the base ref was deleted, recreate it (e.g. from the remote tracking ref) and re-traverse the workspace."],"exampleFix":"// before\nlet outcome = but_workspace::branch::move_branch(editor, &subject, &target)?;\n\n// after\nlet ws = successful_rebase.overlayed_graph()?.into_workspace()?;\nensure!(\n    ws.lower_bound_segment_id\n        .and_then(|id| ws.graph[id].ref_name())\n        .is_some(),\n    \"workspace has no common base ref; set a target branch first\"\n);\nlet outcome = but_workspace::branch::move_branch(editor, &subject, &target)?;","handlingStrategy":"validation","validationCode":"let ws = successful_rebase.overlayed_graph()?.into_workspace()?;\nlet has_base_ref = ws\n    .lower_bound_segment_id\n    .map(|id| &ws.graph[id])\n    .and_then(|segment| segment.ref_name())\n    .is_some();\nif !has_base_ref {\n    // set a target branch for the workspace before tearing off\n    return Ok(None);\n}","typeGuard":null,"tryCatchPattern":"match move_branch(editor, &subject, &target) {\n    Ok(outcome) => { /* ... */ }\n    Err(err) if err.to_string().contains(\"workspace common base\") => {\n        // prompt user to pick a target branch for the workspace\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Always configure a target/base branch before offering tear-off moves.","After deleting a base ref, re-sync the workspace before further moves.","In batch automation, skip tear-off when the workspace lower bound has no ref name."],"tags":["gitbutler","workspace","move-branch","tear-off","rust"],"backgroundTag":"missing-workspace-base-ref","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}