GitoxideLabs/gitoxide · error
change ID is ambiguous in the Tix view; candidates
Error message
change ID {change_id} is ambiguous in the Tix view; candidates:
{candidates} What it means
`relocate_after_editor` expects the recorded change ID to resolve to exactly one commit in the Tix view. If the candidate list contains more than one commit, the target is ambiguous and relocation cannot proceed safely, so the error lists all matching candidate commits (short-displayed via `crate::change_id::display_short`).
Solutions
- Inspect the listed candidate commits and disambiguate manually (rebase/drop the duplicate) before retrying.
- Refresh or repair the Tix view so each change ID maps to exactly one commit, then retry the reword.
- Avoid operations that duplicate a change (e.g. cherry-picking a change ID already in the view) or resolve the duplication first.
- If duplicates are intentional, use a commit ID directly instead of relocating by change ID.
Defensive patterns
Strategy: validation
Validate before calling
let matches: Vec<_> = candidate_ids.into_iter().filter(|id| crate::change_id::for_commit(repo, *id).map_or(false, |c| c == change_id)).collect();
if matches.len() != 1 { /* resolve duplicates before relocating */ } Try / catch
match relocate_after_editor(repo, change_id) {
Ok(res) => res,
Err(e) if e.to_string().contains("is ambiguous") => {
// prompt user to pick among candidates printed in the error
disambiguate(repo, change_id)?
}
Err(e) => return Err(e),
} Prevention
- Never cherry-pick or duplicate a commit whose change ID is already present in the view.
- Repair duplicate change IDs after history rewrites before resuming stacked operations.
- Keep Tix metadata under tool control; avoid manual edits.
When it happens
Trigger: Calling `relocate_after_editor` (via `relocates_an_editor_reword_onto_a_concurrent_amend` or `editor_relocation_requires_one_visible_commit`) when `crate::change_id::for_commit` matches two or more commits in the candidate set — e.g. a change ID duplicated across rewritten/merged history.
Common situations: Duplicate change IDs after a history rewrite that kept two copies of the same logical change (e.g. cherry-pick or rebase duplicates); concurrent operations creating divergent commits sharing a change ID; corrupted or manually edited Tix metadata.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- change ID prefix is ambiguous in the default Tix view
- change ID is no longer present in the Tix view
- the revisions have multiple editable fork points
- --to is ambiguous; candidates: travel to one directly with…
- the edited commit message is empty
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/ac4fad08088d2a0c.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/reword.rs:70
change_id: gix::hash::ChangeId,
) -> Result<(crate::history::HistoryGraph, gix::ObjectId)> {
let graph = super::loaded_view_graph_with_hidden(repo, revisions, hidden_revisions)?;
let mut matches = Vec::new();
for id in graph.stored_commit_ids() {
if crate::change_id::for_commit(repo, id)? == change_id {
matches.push(id);
}
}
match matches.as_slice() {
[target] => Ok((graph, *target)),
[] => anyhow::bail!("change ID {change_id} is no longer present in the Tix view"),
candidates => {
let candidates = candidates
.iter()
.map(|id| crate::change_id::display_short(repo, *id))
.collect::<Result<Vec<_>>>()?
.join("\n ");
anyhow::bail!("change ID {change_id} is ambiguous in the Tix view; candidates:\n {candidates}")
}
}
}
#[tracing::instrument(skip_all, fields(commit_id = %id))]
pub(crate) fn document(repo: &gix::Repository, id: gix::ObjectId) -> Result<(gix::command::Prepare, Vec<u8>)> {
document_with_author(repo, id, None)
}
pub(crate) fn document_with_author(
repo: &gix::Repository,
id: gix::ObjectId,
author: Option<&[u8]>,
) -> Result<(gix::command::Prepare, Vec<u8>)> {
let editor = repo
.editor_command()
.context("could not prepare Git editor")?
.context("no Git editor is available")?;View on GitHub (pinned to e73179060b)