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

  1. Ensure the undo queue ref points only at commits created by the undo API (which always use the empty tree)
  2. Reset the queue ref to a fresh sentinel commit created by the library
  3. 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

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


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)