gitbutlerapp/gitbutler · error

snapshot checkout commit is null

Error message

snapshot checkout commit is null

What it means

The snapshot's `checkout/commit` blob parsed to a valid object id that is the null oid. Restore refuses to check out the null commit, treating the snapshot's checkout record as corrupt or incomplete.

Source

Thrown at crates/gitbutler-oplog/src/oplog.rs:548

    };
    let commit_entry = snapshot_tree
        .lookup_entry_by_path("checkout/commit")?
        .context("snapshot checkout ref has no commit")?;
    let ref_blob = repo
        .find_blob(ref_entry.id())
        .context("failed to read snapshot checkout ref")?;
    let ref_name = gix::refs::FullName::try_from(ref_blob.data.as_bstr())
        .context("snapshot checkout ref is invalid")?;
    if ref_name.category() != Some(gix::refs::Category::LocalBranch) {
        bail!("snapshot checkout ref is not a local branch");
    }
    let commit_blob = repo
        .find_blob(commit_entry.id())
        .context("failed to read snapshot checkout commit")?;
    let commit_id = gix::ObjectId::from_hex(&commit_blob.data)
        .context("snapshot checkout commit is invalid")?;
    if commit_id.is_null() {
        bail!("snapshot checkout commit is null");
    }
    Ok(Some(SnapshotCheckout {
        ref_name,
        commit_id,
    }))
}

fn snapshot_metadata(
    snapshot_tree: &gix::Tree<'_>,
    repo: &gix::Repository,
) -> Result<(ProjectMeta, VirtualBranches)> {
    let vb_toml_entry = snapshot_tree
        .lookup_entry_by_path("virtual_branches.toml")?
        .context("failed to get virtual_branches.toml blob")?;
    let vb_toml_blob = repo
        .find_blob(vb_toml_entry.id())
        .context("failed to convert virtual_branches.toml tree entry to blob")?;
    let SnapshotVirtualBranches {

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Restore an earlier snapshot entry
  2. Repair the `checkout/commit` field to the intended commit id if the snapshot must be used
  3. Report if the snapshot came from the currently running version
Defensive patterns

Strategy: validation

Validate before calling

let commit_id = gix::ObjectId::from_hex(&commit_blob.data)?;
if commit_id.is_null() {
    return Err(anyhow::anyhow!("snapshot checkout commit is null; refusing"));
}

Type guard

fn is_usable_commit_id(id: gix::ObjectId) -> bool {
    !id.is_null()
}

Try / catch

match oplog.restore(snapshot_id) {
    Err(err) if err.to_string().contains("checkout commit is null") => { /* restore an earlier snapshot */ }
    other => other,
}

Prevention

When it happens

Trigger: Restoring a snapshot whose checkout commit field is all zeros.

Common situations: Truncated or hand-edited snapshot trees; placeholder data written by buggy versions; partially failed snapshot writes.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/f8e8616635f401fb. Report an issue: GitHub.