GitoxideLabs/gitoxide · error
the undo queue records itself
Error message
the undo queue records itself
What it means
The undo metadata must never contain an entry for the undo queue ref itself; the queue records changes to other references only. `parse_config` rejects any `[ref "..."]` section whose reference name is the queue ref (as detected by `is_queue_ref`), preventing recursive/self-referential undo state that would corrupt undo/redo semantics.
Solutions
- Remove the `[ref "..."]` section whose name matches the undo queue ref from the metadata
- Re-record the undo state by re-running the tix operation so it is regenerated correctly
- Verify no script or hook writes changes to the queue ref into undo metadata
- Update to a tix version that filters the queue ref when serializing
Example fix
// before [undo] version = v1 [ref "refs/tix/undo/queue"] before = missing after = object:def456 // after (queue section removed) [undo] version = v1 [ref "refs/heads/main"] before = missing after = object:abc123
Defensive patterns
Strategy: validation
Validate before calling
// detect a self-referential queue entry before parsing
let queue_ref = "refs/tix/undo/queue";
let config = gix::config::File::try_from(body.as_ref())?;
for s in config.sections() {
if s.header().name() == b"ref" {
let name = s.header().subsection_name().unwrap_or_default();
assert!(name != queue_ref, "undo queue records itself");
}
} Type guard
fn is_queue_ref(name: &bstr::BStr) -> bool {
name.starts_with(b"refs/tix/undo/")
} Try / catch
match parse_undo_metadata(&repo, &body) {
Ok(changes) => changes,
Err(e) if e.to_string().contains("records itself") => {
eprintln!("self-referential undo state; rebuilding");
rebuild_undo_state(&repo)?
}
Err(e) => return Err(e.into()),
} Prevention
- Exclude the queue ref when writing undo metadata
- Avoid custom scripts that write tix refs directly
- Regenerate undo state rather than patching it by hand
- Keep tix updated so writer-side filtering bugs are fixed
When it happens
Trigger: Parsing undo metadata that contains a section like `[ref "refs/tix/undo/queue"]` — possible if a ref change targeting the queue was serialized by a buggy or tampered-with writer, or if the queue ref was renamed/repointed manually.
Common situations: Hand-editing the undo metadata, custom scripts writing tix refs, or an older/patched tix build that failed to exclude the queue ref when recording changes.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- undo metadata contains an unknown section
- undo reference sections are duplicated or out of order
- the undo queue is not a selectable revision
- an undo operation title cannot be empty
- an undo operation title must be one line
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/5b449384cdd17b63.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/undo.rs:621
ensure_exact_keys(&undo, &["version"])?;
ensure!(
undo.value("version").as_ref().map(|value| value.as_slice()) == Some(VERSION.as_bytes()),
"unsupported undo metadata version"
);
let mut changes = Vec::new();
let mut previous_name: Option<FullName> = None;
for section in sections {
ensure!(
section.header().name() == b"ref",
"undo metadata contains an unknown section"
);
let subsection = section
.header()
.subsection_name()
.context("an undo ref section has no reference name")?;
let name = FullName::try_from(subsection).context("an undo entry contains an invalid reference name")?;
ensure!(!is_queue_ref(name.as_bstr()), "the undo queue records itself");
if let Some(previous) = &previous_name {
ensure!(
previous < &name,
"undo reference sections are duplicated or out of order"
);
}
previous_name = Some(name.clone());
ensure_exact_keys(§ion, &["before", "after"])?;
let before = section.value("before").context("an undo ref has no before-state")?;
let before = parse_state(repo, before.as_bstr())?;
let after = section.value("after").context("an undo ref has no after-state")?;
let after = parse_state(repo, after.as_bstr())?;
ensure!(before != after, "an undo ref does not change");
changes.push(RefChange { name, before, after });
}
Ok(changes)
}
View on GitHub (pinned to e73179060b)