gitbutlerapp/gitbutler · error

No branch found for ID: {branch_id}

Error message

No branch found for ID: {branch_id}

What it means

Forge review commands that operate on lanes resolve the user-supplied ID through the IdMap and keep only results that are `CliId::Branch` (review.rs:462-468). If nothing survives the filter — the ID is unknown, or it resolved only to non-branch entities like commits or uncommitted files — the command bails with 'No branch found for ID'.

Source

Thrown at crates/but/src/command/legacy/forge/review.rs:469

        }
    }
    Ok(branches_without_prs)
}

fn get_branch_names(project: &Project, branch_id: &str) -> anyhow::Result<Vec<String>> {
    let ctx = Context::new_from_legacy_project(project.clone())?;
    let id_map = IdMap::legacy_new_from_context(&ctx)?;
    let branch_ids = id_map
        .parse_using_context(branch_id, &ctx)?
        .iter()
        .filter_map(|clid| match clid {
            CliId::Branch(branch) => Some(branch.name.clone()),
            _ => None,
        })
        .collect::<Vec<_>>();

    if branch_ids.is_empty() {
        anyhow::bail!("No branch found for ID: {branch_id}");
    }

    Ok(branch_ids)
}

#[expect(clippy::too_many_arguments)]
pub async fn handle_multiple_branches_in_workspace(
    ctx: &mut Context,
    review_map: &std::collections::HashMap<String, Vec<but_forge::ForgeReview>>,
    applied_stacks: &[HeadInfoStack],
    skip_force_push_protection: bool,
    with_force: bool,
    run_hooks: bool,
    default_message: bool,
    draft: bool,
    message: Option<&ForgeReviewMessage>,
    out: &mut OutputChannel,
    selected_branches: Option<Vec<String>>,

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Run `but status` in the same repo and copy an ID from the branches/lanes section.
  2. If the ID looks right, refresh it: the workspace may have changed (rebase/squash) since you copied it.
  3. Make sure you are in the right project directory; the IdMap is per-workspace.
Defensive patterns

Strategy: validation

Validate before calling

# Confirm the ID names a lane before running branch-scoped review commands
but status | grep -F '<id>' || { echo 'unknown or non-branch id'; exit 2; }

Type guard

// Narrow IdMap results to branches before use
let branches: Vec<_> = ids.into_iter().filter(|id| matches!(id, CliId::Branch(_))).collect();
if branches.is_empty() {
    // reject before calling the review API
}

Prevention

When it happens

Trigger: Passing a commit ID or uncommitted-file ID where a branch/lane ID is required (branch-scoped review operations); a typo'd or stale short ID that no longer resolves to a lane in this workspace.

Common situations: Copying the wrong ID kind from `but status`; short IDs going stale after the workspace rebases or rewrites history; running the command in a different repo than the one `but status` was run in.

Related errors


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