GitoxideLabs/gitoxide · error
undo metadata has missing, repeated, or unknown keys
Error message
undo metadata has missing, repeated, or unknown keys
What it means
`ensure_exact_keys` compares the section's actual value names against the exact expected list and rejects any mismatch: a missing key, a duplicated key, or an extra unknown key. This enforces a strict schema for undo metadata sections so parsing downstream can assume every expected key exists exactly once.
Solutions
- Make each section contain exactly the expected keys, each once: `before` and `after`, with no extras.
- Fix typos in key names (`befor` -> `before`).
- Remove obsolete/unknown keys added by other tool versions.
- Regenerate the undo metadata with the writing tool rather than hand-editing; if new keys are legitimate, update the expected list in `ensure_exact_keys`.
Example fix
// before [undo-ref "refs/heads/main"] befor = object:1a2b3c... after = object:9f8e7d... comment = note // after [undo-ref "refs/heads/main"] before = object:1a2b3c... after = object:9f8e7d...
Defensive patterns
Strategy: validation
Validate before calling
fn section_keys_valid(section: &gix::config::file::SectionRef<'_>) -> bool {
let names: Vec<_> = section.value_names().collect();
names == ["before", "after"]
} Try / catch
match parse_undo_metadata(&repo, &text) {
Err(e) if e.to_string().contains("undo metadata has missing, repeated, or unknown keys") => {
eprintln!("Each section needs exactly one `before` and one `after` key, no extras");
}
res => res?,
} Prevention
- Use a writer function (not hand edits) to emit undo sections
- Check key spelling: only `before` and `after` are accepted
- Diff metadata files against a known-good sample before use
- When adding fields, update both writer and `ensure_exact_keys` in the same change
When it happens
Trigger: `parse_config` calls `ensure_exact_keys(§ion, &["before", "after"])` (undo.rs:642) on a section that lacks one of the keys, repeats a key, or contains additional keys such as a typo (`befor`) or a comment-like unknown entry.
Common situations: Hand-editing the undo metadata and misspelling `before`/`after`; an older or newer tool version writing extra fields; accidentally duplicating a key when editing; copy-pasting sections and leaving stray keys behind.
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
- an undo ref does not change
- an undo object ID uses the wrong hash kind
- undo/redo cannot delete a worktree HEAD
- a projected worktree reference contains a symbolic cycle
- cannot delete an already-missing reference
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/7a0be7c054beac4f.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/undo.rs:642
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();
ensure!(
actual == expected,
"undo metadata has missing, repeated, or unknown keys"
);
Ok(())
}
fn parse_state(repo: &gix::Repository, value: &BStr) -> Result<State> {
if value == b"missing" {
return Ok(State::Missing);
}
if let Some(hex) = value.strip_prefix(b"object:") {
let id = ObjectId::from_hex(hex).context("an undo object ID is invalid")?;
ensure!(
id.kind() == repo.object_hash(),
"an undo object ID uses the wrong hash kind"
);
return Ok(State::Object(id));
}View on GitHub (pinned to e73179060b)