GitoxideLabs/gitoxide · error

expected exactly one hexadecimal commit ID

Error message

expected exactly one hexadecimal commit ID

What it means

`resolve_pasted_commit` validates that a pasted string is a non-empty, pure ASCII-hexadecimal token before resolving it against the repository with `rev_parse`. The `anyhow::ensure!` fires when the pasted text is empty or contains any non-hex character, since only a full hexadecimal commit ID is accepted in this UI path.

Solutions

  1. Paste only the raw hexadecimal commit ID (40 or 64 hex chars depending on the repo hash).
  2. Strip decorations/prefixes: copy just the OID, e.g. via `git rev-parse <name>` first.
  3. If you need to accept symbolic names or short hashes, extend validation in `resolve_pasted_commit` to try `rev_parse` with gix's built-in prefix handling instead of requiring full hex.
  4. Trim surrounding whitespace/newlines before passing the string (the code already trims, but the clipboard content must still be pure hex).

Example fix

// before
let pasted = "commit 1a2b3c4..."; // copied from git log
resolve_pasted_commit(&repo, pasted)?;
// after
let pasted = pasted.split_whitespace().last().expect("token from log line");
resolve_pasted_commit(&repo, pasted)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_pasted_valid(pasted: &str) -> bool {
    let h = pasted.trim();
    !h.is_empty() && h.bytes().all(|b| b.is_ascii_hexdigit())
}

Try / catch

match resolve_pasted_commit(&repo, pasted) {
    Err(e) if e.to_string().contains("expected exactly one hexadecimal commit ID") => {
        eprintln!("Paste a raw hexadecimal OID, not a branch name or decorated line");
    }
    res => res?,
}

Prevention

When it happens

Trigger: Pasting into the interactive commit-pick flow a string that is empty, whitespace-only after trim, contains prefixes like `HEAD~1`, branch names, short refs, or any non-hex characters (gix-tix/src/lib.rs:7017).

Common situations: Copying `git log`-style lines that include `commit <sha>` prefixes or decorations; pasting symbolic names like `main` or `origin/main`; trailing punctuation or whitespace from a terminal; pasting a full OID with typos.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/2cb13d8540aeec0b. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/lib.rs:7017

                _ => None,
            };
            selected.map_or(CommandMenuInput::Handled, |id| {
                CommandMenuInput::Submit(
                    commands
                        .iter()
                        .find(|command| command.id == id)
                        .expect("a submitted command came from the current catalog")
                        .action
                        .clone(),
                )
            })
        }
    }
}

fn resolve_pasted_commit(repository: &gix::Repository, pasted: &str) -> Result<gix::ObjectId> {
    let hash = pasted.trim();
    anyhow::ensure!(
        !hash.is_empty() && hash.bytes().all(|byte| byte.is_ascii_hexdigit()),
        "expected exactly one hexadecimal commit ID"
    );
    let object = repository
        .rev_parse(hash.as_bytes().as_bstr())
        .context("could not resolve pasted commit ID")?
        .single()
        .context("pasted commit ID is ambiguous")?
        .object()
        .context("could not read pasted object")?;
    anyhow::ensure!(
        object.kind == gix::object::Kind::Commit,
        "pasted object is not a commit"
    );
    Ok(object.id)
}

fn diagnostic_key(character: char) -> KeyEvent {

View on GitHub (pinned to e73179060b)