GitoxideLabs/gitoxide · error
the undo queue first-parent chain contains a cycle
Error message
the undo queue first-parent chain contains a cycle
What it means
`is_queue_commit` follows the first-parent chain of the undo queue tip (or cursor) commit to decide whether a given object id is part of the queue. A `HashSet` of visited ids enforces termination; if a commit id repeats, the first-parent chain is cyclic, which valid commit graphs cannot produce, so this error is raised.
Solutions
- Verify the queue commit graph with `git log --first-parent <queue-tip>` and `git fsck`.
- Rebuild or discard the undo queue ref if its history is corrupt.
- If constructing queue commits in code, ensure each new commit's parent is a previously unvisited (strictly older) commit.
Example fix
// before: linking a commit back into the queue, creating a loop let new = commit(parent_id /* an ancestor that loops */); // after: parent must be the previous tip, advancing the chain let new = commit(queue_tip_id);
Defensive patterns
Strategy: validation
Validate before calling
// confirm the queue tip's first-parent history is linear before planning undo
let out = std::process::Command::new("git")
.args(["rev-list", "--first-parent", tip_id.to_string().as_str()])
.output()?;
// duplicate ids in output => cyclic/corrupt chain, do not call undo APIs Prevention
- Only build queue commits whose parent is the immediate previous queue tip.
- Run `git fsck` after any history rewrite near the queue.
- Never point queue refs at arbitrary user-made commits.
When it happens
Trigger: Undo planning via `is_queue_commit` when the undo-queue tip commit's first-parent ancestry loops back on itself, e.g. commit A's first-parent chain reaches A again via corrupted or forged commit objects.
Common situations: Object store corruption or hand-crafted commit objects; a buggy external tool rewrote history into a loop; tests injecting deliberately cyclic commits.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- could not decode commit-graph parent
- At least one object couldn't be looked up even though it…
- could not read reference
- a symbolic reference chain contains a cycle
- a projected worktree reference contains a symbolic cycle
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/9230f1aa6b683612.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/undo.rs:141
ensure!(seen.insert(name.clone()), "a symbolic reference chain contains a cycle");
let Some(reference) = repo.try_find_reference(name.as_ref())? else {
return Ok(false);
};
let target = reference.target();
let Some(next) = target.try_name() else {
return Ok(false);
};
name = next.to_owned();
}
}
pub(crate) fn is_queue_commit(repo: &gix::Repository, needle: ObjectId) -> Result<bool> {
let Some(mut id) = read_queue_ref(repo, TIP_REF)?.or(read_queue_ref(repo, CURSOR_REF)?) else {
return Ok(false);
};
let mut seen = HashSet::new();
loop {
ensure!(seen.insert(id), "the undo queue first-parent chain contains a cycle");
let Ok(stored) = parse_commit(repo, id) else {
return Ok(false);
};
if id == needle {
return Ok(true);
}
let Some(parent) = stored.parent else {
return Ok(false);
};
id = parent;
}
}
pub(crate) fn review_blocks_undo(repo: &gix::Repository) -> Result<bool> {
let references = repo.references().context("could not open review references")?;
for reference in references
.prefixed(crate::history::REVIEW_PREFIX.as_bstr())
.context("could not iterate review references")?View on GitHub (pinned to e73179060b)