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
- Restore an earlier snapshot entry
- Repair the `checkout/commit` field to the intended commit id if the snapshot must be used
- 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
- Refuse to write null oids into snapshot blobs
- Exercise restore paths with generated snapshots in CI
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
- targetCommitId in project_meta.toml is null
- snapshot checkout ref is not a local branch
- targetRef in project_meta.toml is not a remote-tracking bran
- Invalid conflict stage '{}'
- commit id mismatch: failed to recreate a commit from its par
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/f8e8616635f401fb.
Report an issue: GitHub.