gitbutlerapp/gitbutler · error · anyhow::Error

Stack has no branches

Error message

Stack has no branches

What it means

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.

Source

Thrown at crates/but/src/command/legacy/teardown.rs:141

    let stacks = match crate::legacy::workspace::applied_stacks(ctx) {
        Ok(stacks) => stacks,
        Err(_e) => {
            try_stack_fixes(ctx, out)?;
            crate::legacy::workspace::applied_stacks(ctx)
                .context("Failed to retrieve stacks after attempting fixes")?
        }
    };

    let target_branch_name = if let Some(checkout_to) = checkout_to {
        checkout_to
    } else {
        if let Some(target_stack) = stacks.first() {
            target_stack
                .branches
                .first()
                .map(|branch| branch.name.clone())
                .ok_or_else(|| anyhow::anyhow!("Stack has no branches"))?
        } else {
            return Err(bad_input(
                "Failed to determine checkout target branch. Specify a target branch with `--checkout-to <branch>`.",
            ).into());
        }
    };

    if let Some(out) = out.for_human() {
        writeln!(
            out,
            "  {}",
            t.success
                .paint(format!("✓ Will check out: {target_branch_name}"))
        )?;
        writeln!(out)?;
    }

    // Uninstall managed hooks before checking out

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Pass the target explicitly: `but teardown --checkout-to <branch>`
  2. Open the project in the GitButler app (or inspect `but status`) and fix or delete the empty stack, then rerun teardown
  3. In scripts, always pass --checkout-to so teardown does not depend on stack contents

Example fix

# before
but teardown   # first stack has no branches -> error
# after
but teardown --checkout-to main
Defensive patterns

Strategy: validation

Validate before calling

let stacks = list_stacks(&mut ctx)?;
let has_target = stacks.first().is_some_and(|s| s.branches.first().is_some());
anyhow::ensure!(has_target, "no branch to check out; pass --checkout-to");

Try / catch

On this error, retry the command with `--checkout-to <known-branch>`; that path bypasses the stack lookup entirely.

Prevention

When it happens

Trigger: `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.

Common situations: Workspaces where every branch of the first stack was already integrated; workspace state left inconsistent by an interrupted teardown.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/107d84b608ef23c0. Report an issue: GitHub.