{"record":{"id":"e77031936b8032d8","repo":"GitoxideLabs/gitoxide","slug":"upper-match-already-assured-we-only-deal-with-blob","errorCode":null,"errorMessage":"upper match already assured we only deal with blobs","messagePattern":"upper match already assured we only deal with blobs","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-merge/src/tree/function/resolve.rs","lineNumber":2088,"sourceCode":"    }\n}\n\n/// Merge modes derived from the same ancestor mode, `prev`.\n///\n/// Equal modes are retained. If blob modes differ only in their executable bit, the side that differs from `prev` wins,\n/// preserving either a one-sided enable or disable of that bit.\nfn merge_modes_prev(a: EntryMode, b: EntryMode, prev: EntryMode) -> Option<EntryMode> {\n    match (a.kind(), b.kind()) {\n        (_, _) if a == b => Some(a),\n        (a @ EntryKind::BlobExecutable, b @ (EntryKind::BlobExecutable | EntryKind::Blob))\n        | (a @ EntryKind::Blob, b @ EntryKind::BlobExecutable) => {\n            let prev = prev.kind();\n            let changed = if a == prev { b } else { a };\n            Some(\n                match (prev, changed) {\n                    (EntryKind::Blob, EntryKind::BlobExecutable) => EntryKind::BlobExecutable,\n                    (EntryKind::BlobExecutable, EntryKind::Blob) => EntryKind::Blob,\n                    _ => unreachable!(\"upper match already assured we only deal with blobs\"),\n                }\n                .into(),\n            )\n        }\n        _ => None,\n    }\n}\n\nfn push_deferred(change_and_idx: (Change, Option<usize>), changes: &mut ChangeList) {\n    push_deferred_with_rewrite(change_and_idx, None, changes);\n}\n\nfn push_deferred_with_rewrite(\n    (change, ours_idx): (Change, Option<usize>),\n    new_location: Option<(BString, usize)>,\n    changes: &mut ChangeList,\n) {\n    changes.push(TrackedChange::new(change, Some(ours_idx), new_location));","sourceCodeStart":2070,"sourceCodeEnd":2106,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-merge/src/tree/function/resolve.rs#L2070-L2106","documentation":"In `gix-merge`'s `merge_modes_prev` helper, an upper match already established that both entry kinds are blob variants (regular vs executable). The `unreachable!` fires if any other `EntryKind` (e.g. Link, Tree, Commit) reaches this code, meaning the earlier filter invariant was violated.","triggerScenarios":"Only when mode-merge logic receives a non-blob entry pair, which the enclosing match is supposed to exclude; effectively a guard against future refactors or enum changes.","commonSituations":"Not reachable in normal `gix_merge::tree` merges; would appear as a panic during mode resolution if entry-kind filtering regressed.","solutions":["Report upstream with the trees/modes involved if it fires.","Upgrade `gix-merge` to the latest version.","If maintaining, narrow the outer match or return an explicit error instead of the wildcard `unreachable!`."],"exampleFix":"// before\n_ => unreachable!(\"upper match already assured we only deal with blobs\"),\n// after\nkinds => return Err(message!(\"unexpected entry kinds {kinds:?} in mode merge\"))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Not user-triggerable; isolate with catch_unwind around tree merges.","preventionTips":["Keep gix-merge and gix-object versions in lockstep","Cover mode-change merges (chmod +x toggles) in your test suite"],"tags":["rust","panic","internal-invariant","entry-mode"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}