gitbutlerapp/gitbutler · error

Branch not found

Error message

Branch not found: {branch_name}

What it means

`absorption_plan_with_perm` computes an absorb plan from workspace stacks/assignments, filtering for the stack whose applied segment's shortened ref name equals `branch_name`. If no stack's segment matches, it throws "Branch not found: {branch_name}". It means the requested branch is not an applied segment in the current workspace.

Solutions

  1. List applied workspace branches (`but branch list`) and use the exact short name shown.
  2. Strip any `refs/heads/` prefix and remote prefixes from the branch name before calling.
  3. Apply the stack to the workspace first if it is unapplied.
  4. Verify the branch belongs to the workspace you are querying, not another worktree.

Example fix

// before
absorption_plan(repo, "refs/heads/feature")?;
// after
absorption_plan(repo, "feature")?; // exact short branch name of an applied stack
Defensive patterns

Strategy: validation

Validate before calling

// verify the branch is an applied stack segment before planning absorb
let ws = ctx.workspace()?;
let applied = ws.stacks.iter().any(|s|
    s.segments.iter().any(|seg|
        seg.ref_info.as_ref().is_some_and(|ri| ri.ref_name.shorten() == branch.as_bytes())));
if !applied { return Err(anyhow::anyhow!("{branch} is not an applied workspace branch")); }

Try / catch

match absorption_plan(ctx, branch) {
    Err(e) if e.to_string().starts_with("Branch not found:") =>
        eprintln!("apply the branch to the workspace first"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling the absorption_plan API with a branch name that is not the shortened ref name of any applied stack segment — branch unapplied, branch name given with a prefix (e.g. `refs/heads/` or `origin/`), or the branch exists but has no matching `ref_info` segment.

Common situations: Absorbing into a branch that was unapplied from the workspace; passing a remote-tracking name instead of the local name; case or slash mismatches in the branch name; running before any commits exist on the stack segment.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/29f9074580e42a9a. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-api/src/legacy/absorb.rs:145

            let all_assignments = worktree_changes.assignments;
            let dependencies = worktree_changes.dependencies;

            // Get the stack ID for this branch
            let workspace = crate::legacy::workspace::head_info(ctx)?;

            // Find the stack that contains this branch
            let stack = workspace
                .stacks
                .iter()
                .find(|stack| {
                    stack.segments.iter().any(|segment| {
                        segment
                            .ref_info
                            .as_ref()
                            .is_some_and(|ri| ri.ref_name.shorten() == branch_name.as_bytes())
                    })
                })
                .ok_or_else(|| anyhow::anyhow!("Branch not found: {branch_name}"))?;

            let stack_id = stack.id.ok_or_else(|| anyhow::anyhow!("Stack has no ID"))?;

            // Filter assignments to just this stack
            let candidates: Vec<AbsorbCandidate> = all_assignments
                .into_iter()
                .filter(|a| a.stack_id == Some(stack_id))
                .map(Into::into)
                .collect();

            if candidates.is_empty() {
                anyhow::bail!("No uncommitted changes assigned to branch: {branch_name}");
            }

            (candidates, dependencies)
        }
        AbsorptionTarget::TreeChanges {
            changes,

View on GitHub (pinned to 58e5313667)