{"record":{"id":"62ef047982a37cb9","repo":"gitbutlerapp/gitbutler","slug":"snapshot-additional-ref-target-is-null","errorCode":null,"errorMessage":"snapshot additional ref target is null","messagePattern":"snapshot additional ref target is null","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gitbutler-oplog/src/oplog.rs","lineNumber":568,"sourceCode":") -> Result<Option<SnapshotReference>> {\n    let Some(name_entry) = snapshot_tree.lookup_entry_by_path(\"additional-ref/name\")? else {\n        return Ok(None);\n    };\n    let name_blob = repo.find_blob(name_entry.id())?;\n    let ref_name = gix::refs::FullName::try_from(name_blob.data.as_bstr())\n        .context(\"snapshot additional ref is invalid\")?;\n    if ref_name.category() != Some(gix::refs::Category::LocalBranch) {\n        bail!(\"snapshot additional ref is not a local branch\");\n    }\n    let target = snapshot_tree\n        .lookup_entry_by_path(\"additional-ref/target\")?\n        .map(|entry| {\n            let blob = repo.find_blob(entry.id())?;\n            gix::ObjectId::from_hex(&blob.data).context(\"snapshot additional ref target is invalid\")\n        })\n        .transpose()?;\n    if target.is_some_and(|target| target.is_null()) {\n        bail!(\"snapshot additional ref target is null\");\n    }\n    Ok(Some(SnapshotReference { ref_name, target }))\n}\n\nfn snapshot_checkout(\n    snapshot_tree: &gix::Tree<'_>,\n    repo: &gix::Repository,\n) -> Result<Option<SnapshotCheckout>> {\n    let Some(ref_entry) = snapshot_tree.lookup_entry_by_path(\"checkout/ref\")? else {\n        return Ok(None);\n    };\n    let commit_entry = snapshot_tree\n        .lookup_entry_by_path(\"checkout/commit\")?\n        .context(\"snapshot checkout ref has no commit\")?;\n    let ref_blob = repo\n        .find_blob(ref_entry.id())\n        .context(\"failed to read snapshot checkout ref\")?;\n    let ref_name = gix::refs::FullName::try_from(ref_blob.data.as_bstr())","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/gitbutler-oplog/src/oplog.rs#L550-L586","documentation":"This error is thrown by `snapshot_reference` when an additional reference recorded in a snapshot resolves to a blob whose contents are the all-zero object ID. GitButler stores extra refs (e.g. applied branch heads) inside snapshot trees as blobs containing a hex object id; a null id means the snapshot data is corrupt or was written from a repo that had no valid target. The library refuses to construct a `SnapshotReference` pointing at nothing.","triggerScenarios":"Restoring an oplog snapshot (`restore_snapshot` -> `snapshot_reference`) where a stored additional-ref blob contains hex '0000000000000000000000000000000000000000' (40 zeros).","commonSituations":"Corrupted or hand-edited snapshot data in `.git/gitbutler/` refs; snapshots produced by an older/buggy GitButler version that wrote zero ids; interrupted snapshot writes; manual git plumbing experiments that zeroed ref blobs.","solutions":["Re-run `but oplog restore` on a different (earlier) snapshot entry that has valid ref targets","Inspect the snapshot tree with `git ls-tree` on the oplog snapshot commit and check the blob contents for the affected ref; verify it is a valid 40-char hex sha","Recreate the branch manually from a known commit and take a fresh snapshot instead of restoring the corrupt one","If corruption is widespread, reset the oplog (`but oplog clear`) and continue with a clean history"],"exampleFix":"// corrupt blob: 0000000000000000000000000000000000000000\n// fix: point the stored ref blob at a real commit\n// before: blob data = \"0000000000000000000000000000000000000000\"\n// after:  blob data = \"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0\"","handlingStrategy":"validation","validationCode":"fn valid_snapshot_ref_target(repo: &gix::Repository, entry: &gix::tree::Entry) -> bool {\n    repo.find_blob(entry.id()).ok()\n        .and_then(|b| gix::ObjectId::from_hex(&b.data).ok())\n        .map(|id| !id.is_null())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-edit blobs inside oplog snapshot trees","Check `but doctor`/logs for snapshot corruption warnings before restoring","Keep multiple snapshot entries so a corrupt one can be skipped","Avoid killing the app mid-snapshot-write; let snapshot operations complete"],"tags":["git","snapshot","corruption","null-oid"],"backgroundTag":"checksum-mismatch","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}