GitoxideLabs/gitoxide · error
an undo queue commit does not use the empty tree
Error message
an undo queue commit does not use the empty tree
What it means
Undo queue commits are metadata-only: their tree must be the empty tree since they store reference changes in the commit message body, not in files. `parse_commit` throws this when a commit found on the undo queue has a non-empty tree, meaning it was not created by the undo machinery.
Solutions
- Ensure the undo queue ref points only at commits created by the undo API (which always use the empty tree)
- Reset the queue ref to a fresh sentinel commit created by the library
- If the ref was pointed at a normal branch, create a new dedicated branch for the undo queue
Defensive patterns
Strategy: validation
Validate before calling
let is_empty_tree = commit.tree == gix_hash::ObjectId::empty_tree(repo.object_hash());
Prevention
- Dedicate a ref exclusively to undo queue commits
- Never point the undo queue at a regular branch
- Verify queue commit trees before parsing in defensive code
When it happens
Trigger: Calling `parse_commit` (via `is_queue_commit` or `load`) with a commit ID that points to a regular content commit whose tree is not `ObjectId::empty_tree(hash)`.
Common situations: Pointing the undo queue ref at an ordinary branch tip, mixing normal commits into the undo queue chain, or reusing an existing branch as the undo queue.
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
- the undo sentinel has the wrong title
- the undo sentinel contains reference changes
- an undo commit has invalid retention parents
- At least one object couldn't be looked up even though it…
- could not read reference
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/4b02aa4717cf4a2d.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/undo.rs:839
gix::refs::TargetRef::Symbolic(_) => bail!("{name} must be a direct reference"),
}
}
struct ParsedCommit {
parent: Option<ObjectId>,
title: String,
changes: Vec<RefChange>,
}
fn parse_commit(repo: &gix::Repository, id: ObjectId) -> Result<ParsedCommit> {
let commit = repo
.find_commit(id)
.with_context(|| format!("could not find undo queue commit {id}"))?
.decode()
.context("could not decode an undo queue commit")?
.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");
}View on GitHub (pinned to e73179060b)