GitoxideLabs/gitoxide · error
the undo queue cannot record itself
Error message
the undo queue cannot record itself
What it means
`normalize_changes` validates a batch of reference changes before they are recorded on the undo queue. Any change whose target name is one of the undo queue's own refs (tip, cursor, etc., matched by `is_queue_ref`) is rejected, because recording a change to the queue refs on the queue itself would create self-referential, un-undoable state.
Solutions
- Filter out queue refs from your change list before recording (use the same prefix test the library uses).
- Never write directly to the undo queue's tip/cursor refs; use the library's public undo/redo APIs.
- If you need to reset the queue, use its reset/discard API instead of crafting a RefChange.
Example fix
// before: recording every ref change
let changes: Vec<RefChange> = all_ref_updates();
repo.undo_record(changes)?;
// after: drop queue-internal refs first
let changes: Vec<RefChange> = all_ref_updates()
.into_iter()
.filter(|c| !crate::history::is_queue_ref(c.name.as_bstr()))
.collect(); Defensive patterns
Strategy: validation
Validate before calling
// filter queue-internal refs out of any change batch before recording
let changes: Vec<RefChange> = changes
.into_iter()
.filter(|c| !crate::history::is_queue_ref(c.name.as_bstr()))
.collect(); Prevention
- Never write to refs under the undo queue prefix directly.
- When enumerating all refs for recording, always exclude the queue prefix.
- Use the library's reset/discard APIs to manage queue refs.
When it happens
Trigger: Calling `record`, `changes_from_edits`, or `apply_reversed_changes` with a `RefChange` whose `name` points at an undo-queue ref (e.g. the queue tip/cursor ref).
Common situations: Custom automation that enumerates all refs and builds ref updates blindly, capturing the queue's internal refs; misconfigured tools that treat queue refs as ordinary refs.
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
- successive changes to
- tix stash reference does not use a canonical full commit ID
- rewritten commit already has saved worktree state
- already has saved worktree state
- could not read reference
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/26341cab03f06778.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/undo.rs:341
title,
changes,
edits,
position: queue.position(cursor_index),
})
}
fn empty_position() -> Position {
Position {
title: START_TITLE.into(),
undo: 0,
redo: 0,
}
}
fn normalize_changes(changes: impl IntoIterator<Item = RefChange>) -> Result<Vec<RefChange>> {
let mut by_name = BTreeMap::<FullName, RefChange>::new();
for change in changes {
ensure!(
!is_queue_ref(change.name.as_bstr()),
"the undo queue cannot record itself"
);
match by_name.get_mut(&change.name) {
Some(existing) => {
ensure!(
existing.after == change.before,
"successive changes to {} are not continuous",
change.name
);
existing.after = change.after;
}
None => {
by_name.insert(change.name.clone(), change);
}
}
}
Ok(by_nameView on GitHub (pinned to e73179060b)