{"record":{"id":"107d84b608ef23c0","repo":"gitbutlerapp/gitbutler","slug":"stack-has-no-branches-107d84","errorCode":null,"errorMessage":"Stack has no branches","messagePattern":"Stack has no branches","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but/src/command/legacy/teardown.rs","lineNumber":141,"sourceCode":"\n    let stacks = match crate::legacy::workspace::applied_stacks(ctx) {\n        Ok(stacks) => stacks,\n        Err(_e) => {\n            try_stack_fixes(ctx, out)?;\n            crate::legacy::workspace::applied_stacks(ctx)\n                .context(\"Failed to retrieve stacks after attempting fixes\")?\n        }\n    };\n\n    let target_branch_name = if let Some(checkout_to) = checkout_to {\n        checkout_to\n    } else {\n        if let Some(target_stack) = stacks.first() {\n            target_stack\n                .branches\n                .first()\n                .map(|branch| branch.name.clone())\n                .ok_or_else(|| anyhow::anyhow!(\"Stack has no branches\"))?\n        } else {\n            return Err(bad_input(\n                \"Failed to determine checkout target branch. Specify a target branch with `--checkout-to <branch>`.\",\n            ).into());\n        }\n    };\n\n    if let Some(out) = out.for_human() {\n        writeln!(\n            out,\n            \"  {}\",\n            t.success\n                .paint(format!(\"✓ Will check out: {target_branch_name}\"))\n        )?;\n        writeln!(out)?;\n    }\n\n    // Uninstall managed hooks before checking out","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but/src/command/legacy/teardown.rs#L123-L159","documentation":"During `but teardown` without an explicit --checkout-to, but takes the first branch of the first stack as the branch to check out after tearing the workspace down. If that stack exists but its branches list is empty, there is no checkout target and teardown aborts.","triggerScenarios":"`but teardown` (no --checkout-to) where stacks[0].branches is empty: the stack's branches were all deleted or merged in the GitButler app, or an earlier partial teardown left an empty stack.","commonSituations":"Workspaces where every branch of the first stack was already integrated; workspace state left inconsistent by an interrupted teardown.","solutions":["Pass the target explicitly: `but teardown --checkout-to <branch>`","Open the project in the GitButler app (or inspect `but status`) and fix or delete the empty stack, then rerun teardown","In scripts, always pass --checkout-to so teardown does not depend on stack contents"],"exampleFix":"# before\nbut teardown   # first stack has no branches -> error\n# after\nbut teardown --checkout-to main","handlingStrategy":"validation","validationCode":"let stacks = list_stacks(&mut ctx)?;\nlet has_target = stacks.first().is_some_and(|s| s.branches.first().is_some());\nanyhow::ensure!(has_target, \"no branch to check out; pass --checkout-to\");","typeGuard":null,"tryCatchPattern":"On this error, retry the command with `--checkout-to <known-branch>`; that path bypasses the stack lookup entirely.","preventionTips":["Always pass --checkout-to in scripted teardowns","Delete empty stacks in the workspace before tearing down"],"tags":["teardown","stack","branches","workspace"],"backgroundTag":"empty-collection-state","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}