GitoxideLabs/gitoxide · error
undo reference sections are duplicated or out of order
Error message
undo reference sections are duplicated or out of order
What it means
Undo metadata lists one `[ref "<name>"]` section per changed reference, and these sections must be strictly ordered by reference name with no duplicates. `parse_config` compares each reference name to the previous one and fails when a name is not strictly greater, which indicates either the same reference appears twice or the sections were written out of order.
Solutions
- Sort the `[ref ...]` sections lexicographically by reference name in the metadata
- Remove duplicate sections so each reference name appears exactly once
- Regenerate the undo metadata by re-running the tix operation that wrote it
- Avoid hand-editing undo metadata; let tix serialize it
Example fix
// before (duplicated and out of order) [ref "refs/heads/zebra"] before = missing after = object:111 [ref "refs/heads/alpha"] before = missing after = object:222 [ref "refs/heads/zebra"] before = object:111 after = object:333 // after [ref "refs/heads/alpha"] before = missing after = object:222 [ref "refs/heads/zebra"] before = missing after = object:333
Defensive patterns
Strategy: validation
Validate before calling
// verify ref sections are unique and sorted before parsing
let config = gix::config::File::try_from(body.as_ref())?;
let mut names: Vec<_> = config.sections()
.filter(|s| s.header().name() == b"ref")
.filter_map(|s| s.header().subsection_name().map(|n| n.to_vec()))
.collect();
let sorted = names.clone();
names.sort();
names.dedup();
assert_eq!(names.len(), sorted.len(), "duplicate ref sections");
assert_eq!(sorted, names, "ref sections out of order"); Type guard
fn sections_sorted_unique(names: &[Vec<u8>]) -> bool {
names.windows(2).all(|w| w[0] < w[1])
} Try / catch
match parse_undo_metadata(&repo, &body) {
Ok(changes) => changes,
Err(e) if e.to_string().contains("duplicated or out of order") => {
eprintln!("undo metadata malformed; regenerating");
regenerate_undo_metadata(&repo)?
}
Err(e) => return Err(e.into()),
} Prevention
- Let tix serialize undo metadata; never reorder sections by hand
- Resolve merge conflicts in the metadata by regenerating, not manual editing
- Validate ordering after any tool rewrites config-style files
- Keep one writer per undo metadata ref to avoid concurrent rewrites
When it happens
Trigger: Parsing undo metadata where two `[ref "refs/heads/main"]` sections exist, or where `[ref "refs/heads/zebra"]` precedes `[ref "refs/heads/alpha"]` — from hand-editing, a faulty writer, or a merge that reordered/duplicated sections.
Common situations: Manual edits to the metadata ref, merge conflicts that duplicate or reorder sections, or third-party tooling rewriting the config body without preserving canonical ordering.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- undo metadata contains an unknown section
- the undo queue records itself
- 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/cb9606af28479138.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/undo.rs:623
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)
}
fn ensure_exact_keys(section: &gix::config::file::SectionRef<'_>, expected: &[&str]) -> Result<()> {
let actual: Vec<_> = section.value_names().collect();View on GitHub (pinned to e73179060b)