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
- Run `but status` in the same repo and copy an ID from the branches/lanes section.
- If the ID looks right, refresh it: the workspace may have changed (rebase/squash) since you copied it.
- 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
- Only pass lane/branch IDs (from the branches section of `but status`) to branch-scoped commands.
- Refresh IDs after rebases or workspace updates; short IDs go stale.
- Run commands from the same project directory the IDs came from.
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
- Aborting due to empty PR title
- Could not find branch: {branch_id}
- Ambiguous branch '{branch_id}', matches multiple items
- Expected a branch ID, got {}
- Commit '{commit_id_str}' not found. Try running 'but status'
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/e2834edcaa28e60c.
Report an issue: GitHub.