GitoxideLabs/gitoxide · error

the undo sentinel has the wrong title

Error message

the undo sentinel has the wrong title

What it means

The sentinel is the root commit of the undo queue and must carry the reserved `START_TITLE` title. `parse_commit` throws this when it encounters a parentless queue commit whose title differs, meaning the queue was seeded with a malformed or hand-made root commit.

Solutions

  1. Recreate the undo queue so it starts from a sentinel commit created by the library with the reserved title
  2. Delete the queue ref and record a fresh undo operation to regenerate a valid sentinel
  3. Never manually write the sentinel commit; always initialize via the library
Defensive patterns

Strategy: try-catch

Try / catch

match undo.load(repo) {
    Err(e) if e.to_string().contains("sentinel") => {
        // delete queue ref, re-initialize undo session
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `parse_commit` (via `is_queue_commit` or `load`) on a parentless commit in the undo queue whose title is not `START_TITLE`.

Common situations: Hand-crafting the queue's root commit with a custom message, or using a pre-existing root commit (e.g. an initial repo commit) as the sentinel.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

        .into_owned()
        .context("could not own an undo queue commit")?;
    ensure!(
        commit.tree == ObjectId::empty_tree(repo.object_hash()),
        "an undo queue commit does not use the empty tree"
    );
    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::*;

View on GitHub (pinned to e73179060b)