gitbutlerapp/gitbutler · error

" " is ambiguous. Please provide more characters to…

Error message

"{target}" is ambiguous. Please provide more characters to uniquely identify it.

What it means

Thrown by parse_commit_or_branch when the IdMap returns more than one match for the target — the identifier is a valid prefix but is ambiguous. The user must supply more characters (or a longer name) to make it unique.

Solutions

  1. Provide more characters of the commit hash.
  2. Use the full branch name.
  3. Run `but status` to see which identifiers collide.

Example fix

// before
but resolve ab
// after
but resolve ab34f9c
Defensive patterns

Strategy: validation

Validate before calling

const matches = idMap.parse(target);
if (matches.length > 1) throw new Error(`"${target}" is ambiguous; candidates: ${matches.map(m => m.display).join(', ')}`);

Try / catch

try { await butResolve(prefix) } catch (e) { if (String(e).includes('ambiguous')) { listCandidates(prefix); } }

Prevention

When it happens

Trigger: `but resolve <prefix> ...` where the short commit-hash prefix or partial branch name matches 2+ CliIds in the workspace.

Common situations: Short SHAs that share a prefix; similarly named branches like feature/x and feature/x-2.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at crates/but/src/command/legacy/resolve.rs:714

}

enum CommitOrBranch {
    Commit(gix::ObjectId),
    Branch(String),
}

/// Resolve a user-provided identifier to a commit or a branch.
fn parse_commit_or_branch(ctx: &mut Context, target: &str) -> Result<CommitOrBranch> {
    let id_map = IdMap::legacy_new_from_context(ctx)?;
    let matches = id_map.parse_using_context(target, ctx)?;
    match matches.as_slice() {
        [] => bail!(
            "\"{target}\" is neither a commit nor a branch. Try running 'but status' to see what is available."
        ),
        [CliId::Commit { commit, .. }] => Ok(CommitOrBranch::Commit(commit.commit_id)),
        [CliId::Branch(branch)] => Ok(CommitOrBranch::Branch(branch.name.clone())),
        [_] => bail!("\"{target}\" does not refer to a commit or a branch"),
        _ => bail!(
            "\"{target}\" is ambiguous. Please provide more characters to uniquely identify it."
        ),
    }
}

/// List the conflicts of a conflicted commit without entering resolution mode.
fn list_conflicts(ctx: &mut Context, out: &mut OutputChannel, commit: Option<&str>) -> Result<()> {
    let t = theme::get();
    let Some(target) = target_conflicted_commit(ctx, commit)? else {
        if let Some(human_out) = out.for_human() {
            writeln!(
                human_out,
                "{}",
                t.success.paint("No conflicted commits found.")
            )?;
        }
        if let Some(json_out) = out.for_json() {
            json_out.write_value(serde_json::json!({ "commit_id": null, "files": [] }))?;

View on GitHub (pinned to 58e5313667)