gitbutlerapp/gitbutler · error
Target must be a commit ID or branch, not {}
Error message
Target must be a commit ID or branch, not {} What it means
In `but show` (crates/but/src/command/legacy/show.rs:83), when the argument resolves to exactly one IdMap entry, only CliId::Commit and CliId::Branch are showable. Every other CliId variant (uncommitted file/hunk, path prefix, committed file, the uncommitted area, a worktree, a stack) bails, with kind_for_humans() naming the actual kind.
Source
Thrown at crates/but/src/command/legacy/show.rs:83
commit.id
} else if cli_ids.len() > 1 {
bail!(
"Commit ID '{}' is ambiguous. Found {} matches",
commit_id_str,
cli_ids.len()
);
} else {
match &cli_ids[0] {
CliId::Commit {
commit: CommitId { commit_id, .. },
id: _,
} => *commit_id,
CliId::Branch(branch) => {
// This is a branch identified by CLI ID, show the branch
return show_branch(ctx, out, &branch.name, verbose, &id_map);
}
_ => {
bail!(
"Target must be a commit ID or branch, not {}",
cli_ids[0].kind_for_humans()
);
}
}
};
// Get commit and file details
let repo = ctx.repo.get()?;
let raw_commit = repo.find_commit(commit_id)?;
let decoded = raw_commit.decode()?;
// Get diff with first parent
let parent_id = raw_commit.parent_ids().next().map(|id| id.detach());
let tree_changes = but_core::diff::TreeChanges::from_trees(&repo, parent_id, commit_id)?;
// Extract change-id if present (try both header names)
let change_id = decodedView on GitHub (pinned to caf1f223d3)
Solutions
- Pass a commit SHA or a branch CLI ID to `but show`.
- Use the command matching the entity kind: stack/branch subcommands for stacks and branches, `but status` for uncommitted items.
- Re-run `but status` and read the entity kind shown next to the ID before reusing it.
Example fix
# before but show s7 # s7 is a stack ID # Target must be a commit ID or branch, not a stack # after but branch list # inspect stacks/branches but show 4f2a # a commit short ID
Defensive patterns
Strategy: type-guard
Validate before calling
let ids = id_map.lookup(arg);
if ids.len() == 1 && !matches!(ids[0], CliId::Commit { .. } | CliId::Branch(_)) {
// route to the right command for this kind instead of `but show`
} Type guard
fn is_showable_target(id: &CliId) -> bool {
matches!(id, CliId::Commit { .. } | CliId::Branch(_))
} Try / catch
match cli_ids[0] {
CliId::Commit { .. } | CliId::Branch(_) => { /* proceed */ }
other => anyhow::bail!("not showable: {} — use the matching subcommand", other.kind_for_humans()),
} Prevention
- Check the entity kind printed next to every short ID before passing it to a command.
- In automation, resolve IDs once and dispatch by kind_for_humans().
- Remember `but show` accepts only commit SHAs and branch IDs.
When it happens
Trigger: Running `but show <short-id>` where the ID belongs to a stack, worktree, uncommitted area, committed file, or path prefix — e.g. copying a stack or worktree ID from `but status` output and passing it to show.
Common situations: Assuming every short ID printed by status works with every subcommand; scripted use of IDs without checking their kind; stale docs or examples.
Related errors
- Invalid version: empty string. Usage: but-installer [version
- Invalid version format: {version}. Version must contain only
- Invalid version format: {version}. Version must contain at l
- No branch found for ID: {branch_id}
- Could not find branch: {branch_id}
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/bd1f562ceccc3e38.
Report an issue: GitHub.