gitbutlerapp/gitbutler · error · anyhow::Error
CLI id '{short_id}' is ambiguous for {kind} in IdMap
Error message
CLI id '{short_id}' is ambiguous for {kind} in IdMap What it means
Thrown by `lookup_cli_id_for_short_id`: after filtering IdMap matches by exact short-string equality and the kind predicate, more than one entry survives. The short id is too short to name exactly one entity of that kind, so the command refuses to guess.
Source
Thrown at crates/but/src/command/legacy/status/mod.rs:1855
Ok(())
}
fn lookup_cli_id_for_short_id(
id_map: &IdMap,
repo: &gix::Repository,
short_id: &str,
predicate: impl Fn(&CliId) -> bool,
kind: &str,
) -> anyhow::Result<CliId> {
let mut matches = id_map.parse_using_repo(short_id, repo)?;
matches.retain(|id| id.to_short_string() == short_id && predicate(id));
match matches.len() {
1 => Ok(matches.remove(0)),
0 => Err(anyhow::anyhow!(
"Could not find {kind} CLI id '{short_id}' in IdMap"
)),
_ => Err(anyhow::anyhow!(
"CLI id '{short_id}' is ambiguous for {kind} in IdMap"
)),
}
}
fn status_letter(status: &TreeStatus) -> char {
match status {
TreeStatus::Addition { .. } => 'A',
TreeStatus::Deletion { .. } => 'D',
TreeStatus::Modification { .. } => 'M',
TreeStatus::Rename { .. } => 'R',
}
}
pub fn status_letter_ui(status: &ui::TreeStatus) -> char {
match status {
ui::TreeStatus::Addition { .. } => 'A',
ui::TreeStatus::Deletion { .. } => 'D',View on GitHub (pinned to caf1f223d3)
Solutions
- Use more characters of the id to disambiguate — extend the prefix until it is unique
- List the current ids (`but status` / the relevant list command) to see which entries collide and pick the right one
- In scripts, prefer full-length git shas over short CLI ids to avoid collisions entirely
Example fix
# before: 'c3' matches two entries but <cmd> c3 # after: longer prefix but <cmd> c31
Defensive patterns
Strategy: validation
Validate before calling
let hits: Vec<_> = id_map
.parse_using_repo(short_id, repo)?
.into_iter()
.filter(|id| id.to_short_string() == short_id && kind_predicate(id))
.collect();
if hits.len() > 1 {
anyhow::bail!("'{short_id}' matches {} {kind} ids; extend the prefix", hits.len());
} Try / catch
match lookup_cli_id_for_short_id(id_map, repo, short_id, |i| is_commit(i), "commit") {
Ok(cli_id) => { /* use */ }
Err(err) if err.to_string().contains("ambiguous") => {
// lengthen the prefix by one or more characters and retry
}
Err(err) => return Err(err),
} Prevention
- Extend short ids by a character or two until unique after rewrites/amends
- Re-list ids after history-changing operations; old and new entries coexist and collide
- Use full-length shas in automation to sidestep short-id collisions
When it happens
Trigger: Two commits (or branches) share the same short id string in the IdMap — common right after history-rewriting operations (amend, rebase, ship) that create parallel entries — and the user passes that id to a command resolving a single entity.
Common situations: Short ids after amend/rebase when old and new entries coexist; large workspaces where the short-id space for that kind collided; scripts using a fixed prefix length that is too short for the workspace's size.
Related errors
- Could not find {kind} CLI id '{short_id}' in IdMap
- Commit '{commit_id_str}' not found
- Editor exited with non-zero status
- The repository at {} is bare. GitButler requires a non-bare
- The repository at {} is a non-main worktree. GitButler requi
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/806e87c53e9d1523.
Report an issue: GitHub.