gitbutlerapp/gitbutler · error
targetCommitId in project_meta.toml is null
Error message
targetCommitId in project_meta.toml is null
What it means
The target commit id stored in a snapshot's `project_meta.toml` parsed as a valid hex object id but equals the null oid. Since a null target is meaningless, restore refuses; the field was written with placeholder or corrupt data.
Source
Thrown at crates/gitbutler-oplog/src/oplog.rs:105
type Error = anyhow::Error;
fn try_from(meta: SnapshotProjectMeta) -> Result<Self> {
let target_ref = meta
.target_ref
.map(|name| {
let name: gix::refs::FullName = name
.try_into()
.context("invalid targetRef in project_meta.toml")?;
if name.category() != Some(gix::refs::Category::RemoteBranch) {
bail!("targetRef in project_meta.toml is not a remote-tracking branch");
}
Ok(name)
})
.transpose()?;
let target_commit_id = gix::ObjectId::from_str(&meta.target_commit_id)
.context("invalid targetCommitId in project_meta.toml")?;
if target_commit_id.is_null() {
bail!("targetCommitId in project_meta.toml is null");
}
Ok(Self {
target_ref,
target_commit_id: Some(target_commit_id),
push_remote: meta.push_remote,
})
}
}
/// The Oplog allows for crating snapshots of the current state of the project as well as restoring to a previous snapshot.
/// Snapshots include the state of the working directory as well as all additional GitButler state (e.g. virtual branches, conflict state).
/// The data is stored as git trees in the following shape:
///
/// ```text
/// .
/// ├── checkout/ (ad-hoc checkouts only)
/// │ ├── commit
/// │ └── refView on GitHub (pinned to caf1f223d3)
Solutions
- Restore an earlier snapshot that records a real target commit id
- If the snapshot must be used, repair its metadata tree to record the intended target commit
- Report a bug if the snapshot was produced by the currently running version
Defensive patterns
Strategy: validation
Validate before calling
let id = gix::ObjectId::from_str(&meta.target_commit_id)?;
if id.is_null() {
return Err(anyhow::anyhow!("snapshot has a null targetCommitId; refusing restore"));
} Type guard
fn has_valid_target_commit(meta: &SnapshotProjectMeta) -> bool {
gix::ObjectId::from_str(&meta.target_commit_id).is_ok_and(|id| !id.is_null())
} Try / catch
match oplog.restore(snapshot_id) {
Err(err) if err.to_string().contains("targetCommitId") => { /* choose an earlier snapshot */ }
other => other,
} Prevention
- Reject null object ids when serializing snapshot metadata
- Keep oplog snapshots intact; never edit snapshot trees by hand
When it happens
Trigger: Restoring a snapshot whose `targetCommitId` field is all zeros or an explicit null placeholder.
Common situations: Snapshots written from default/empty ProjectMeta values; truncated or hand-crafted snapshot trees; bugs in older snapshot writers.
Related errors
- snapshot checkout commit is null
- targetRef in project_meta.toml is not a remote-tracking bran
- Invalid conflict stage '{}'
- snapshot checkout ref is not a local branch
- 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/23b59ada9497410d.
Report an issue: GitHub.