GitoxideLabs/gitoxide · error

an undo commit has invalid retention parents

Error message

an undo commit has invalid retention parents

What it means

Undo commits use extra parents (retention parents) to keep referenced history reachable, and `parse_commit` verifies these parents match what `retention_parents` computes from the parent commit and the recorded changes. A mismatch means the commit's parent list was altered or created by a different/incompatible version.

Solutions

  1. Rebuild the undo queue from scratch (delete the ref and re-record operations) so retention parents are recomputed correctly
  2. Check the library version that created the queue matches the one parsing it
  3. Do not rewrite, rebase, or cherry-pick undo queue commits with external git tooling
Defensive patterns

Strategy: try-catch

Try / catch

match undo.load(repo) {
    Err(e) if e.to_string().contains("retention parents") => {
        // treat queue as corrupt; rebuild from scratch
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `parse_commit` (via `is_queue_commit` or `load`) on an undo commit whose `parents` slice differs from the expected retention parents computed for its parent and recorded changes.

Common situations: Queue history rewritten by an external tool, commits created by an older/newer library version with different retention rules, or manual cherry-pick/rebase of queue commits.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/faf6b5e9c2b658ac. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/edit/undo.rs:861

    let message = gix::objs::commit::MessageRef::from_bytes(&commit.message);
    let title = message
        .title
        .to_str()
        .context("an undo operation title is not UTF-8")?
        .to_owned();
    validate_title(&title)?;
    let body = message.body.context("an undo queue commit has no metadata body")?;
    let changes = parse_config(repo, body)?;
    let parent = commit.parents.first().copied();
    match parent {
        None => {
            ensure!(title == START_TITLE, "the undo sentinel has the wrong title");
            ensure!(changes.is_empty(), "the undo sentinel contains reference changes");
        }
        Some(parent) => {
            ensure!(!changes.is_empty(), "an undo operation contains no reference changes");
            let expected = retention_parents(repo, parent, &changes)?;
            ensure!(
                commit.parents.as_slice() == expected,
                "an undo commit has invalid retention parents"
            );
        }
    }
    Ok(ParsedCommit { parent, title, changes })
}

#[cfg(test)]
mod tests {
    use super::*;

    fn repo() -> gix_testtools::Result<(gix_testtools::tempfile::TempDir, gix::Repository)> {
        let fixture = gix_testtools::scripted_fixture_writable("create_commit.sh")?;
        let repository = crate::test_repository::open(fixture.path())?;
        Ok((fixture, repository))
    }

View on GitHub (pinned to e73179060b)