GitoxideLabs/gitoxide · error · anyhow::Error
the undo queue has only one of its tip and cursor references
Error message
the undo queue has only one of its tip and cursor references
What it means
Integrity check in `edit::undo::load`, which restores the undo queue from its TIP and CURSOR references. The queue is only valid when both refs exist together or neither does; if exactly one of the pair is present, the queue is in an inconsistent state (partial write, manual deletion, or corruption) and loading bails instead of planning undo/redo against incomplete data. This error propagates to callers `record`, `position`, `plan_undo`, and `plan_redo`. Fix by restoring the missing ref or clearing both refs to reset the queue.
Solutions
- Restore the missing queue reference: recreate refs/tix/undo/tip or refs/tix/undo/cursor from a backup or by re-deriving it from the other reference
- Delete the surviving queue reference as well so load() sees neither and the undo queue restarts empty
- Fix whatever partial write or external deletion left the pair inconsistent, then retry the undo/redo operation
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at gix-tix/src/edit/undo.rs:768 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/84085d32985a81d4.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/undo.rs:768
fn position(&self, cursor_index: usize) -> Position {
Position {
title: cursor_index
.checked_sub(1)
.and_then(|index| self.entries.get(index))
.map_or_else(|| START_TITLE.into(), |entry| entry.title.clone()),
undo: cursor_index,
redo: self.entries.len() - cursor_index,
}
}
}
fn load(repo: &gix::Repository) -> Result<Option<Queue>> {
let tip = read_queue_ref(repo, TIP_REF)?;
let cursor = read_queue_ref(repo, CURSOR_REF)?;
let (tip, cursor) = match (tip, cursor) {
(None, None) => return Ok(None),
(Some(tip), Some(cursor)) => (tip, cursor),
_ => bail!("the undo queue has only one of its tip and cursor references"),
};
let mut id = tip;
let mut seen = HashSet::new();
let mut entries = Vec::new();
let sentinel;
loop {
ensure!(seen.insert(id), "the undo queue first-parent chain contains a cycle");
let stored = parse_commit(repo, id)?;
match stored.parent {
Some(parent) => {
entries.push(StoredEntry {
id,
title: stored.title,
changes: stored.changes,
});
id = parent;
}View on GitHub (pinned to e73179060b)