{"record":{"id":"6530a5f855a8fd0a","repo":"gitbutlerapp/gitbutler","slug":"snapshot-tree-id-needs-a-head-entry-if-it-has-a-worktree","errorCode":null,"errorMessage":"Snapshot tree {id} needs a 'HEAD' entry if it has a 'worktree' entry","messagePattern":"Snapshot tree (.+?) needs a 'HEAD' entry if it has a 'worktree' entry","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-core/src/snapshot/resolve_tree.rs","lineNumber":98,"sourceCode":"        let worktree_cherry_pick = match (&head_tree, worktree) {\n            (Some(worktree_base), Some(worktree)) => {\n                let base = merge_base_override.unwrap_or_else(|| worktree_base.object_id());\n                let ours = target_worktree_tree_id;\n                let theirs = worktree.object_id();\n\n                repo.merge_trees(\n                    base,\n                    ours,\n                    theirs,\n                    repo.default_merge_labels(),\n                    worktree_cherry_pick_options\n                        .map(Ok)\n                        .unwrap_or_else(|| repo.tree_merge_options())?,\n                )?\n                .into()\n            }\n            (None, Some(_worktree)) => {\n                bail!(\n                    \"Snapshot tree {id} needs a 'HEAD' entry if it has a 'worktree' entry\",\n                    id = snapshot_tree.id\n                )\n            }\n            (None, None) | (Some(_), None) => None,\n        };\n\n        let index = match (&head_tree, index, index_conflicts) {\n            (_, Some(index_tree), Some(index_conflicts)) => {\n                let (mut index, _path) = repo.index_from_tree(&index_tree.id())?.into_parts();\n                replace_entries_with_their_restored_conflicts(&mut index, index_conflicts.id())?;\n                Some(index)\n            }\n            (_, Some(index_tree), None) => {\n                let (index, _path) = repo.index_from_tree(&index_tree.id())?.into_parts();\n                Some(index)\n            }\n            (Some(worktree_base), None, Some(index_conflicts)) => {","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-core/src/snapshot/resolve_tree.rs#L80-L116","documentation":"resolve_tree decodes a snapshot tree into a HEAD tree/index. A snapshot entry 'worktree' is only meaningful relative to a HEAD entry; if a snapshot tree contains 'worktree' but no 'HEAD' entry, resolution cannot proceed and it bails with the tree id.","triggerScenarios":"Resolving a snapshot tree whose entries contain 'worktree' but lack a 'HEAD' entry (invalid or hand-crafted snapshot, partially written snapshot, version mismatch between writer and reader).","commonSituations":"Corrupted or truncated snapshot data; snapshots written by an older/newer GitButler version with different entry conventions; manually constructed snapshot trees in tests.","solutions":["Recreate the snapshot so it contains both 'HEAD' and 'worktree' entries","Drop or rebuild the corrupted snapshot for this project so it is regenerated from current state","Check the snapshot-writing code path to guarantee 'HEAD' is written whenever 'worktree' is"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let has = |k: &str| snapshot_tree.entries.iter().any(|e| e.filename == k);\nif has(\"worktree\") && !has(\"HEAD\") { return Err(anyhow!(\"snapshot missing HEAD entry\")); }","typeGuard":null,"tryCatchPattern":"match resolve_tree(repo, snapshot_tree) { Ok(t) => t, Err(_) => rebuild_snapshot(repo) }","preventionTips":["Never hand-build snapshot trees; use the writer API","Regenerate snapshots after upgrading versions if the format changed","Write 'HEAD' whenever 'worktree' is written"],"tags":["rust","git","snapshot","corrupt-data"],"backgroundTag":"internal-invariant-violation","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"}