{"record":{"id":"f90b10265d7d31ca","repo":"GitoxideLabs/gitoxide","slug":"object-kind-as-set-by-cache","errorCode":null,"errorMessage":"object kind as set by cache","messagePattern":"object kind as set by cache","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gix-pack/src/data/file/decode/entry.rs","lineNumber":297,"sourceCode":"                }\n                Header::RefDelta { base_id } => match resolve(base_id.as_ref(), out) {\n                    Some(ResolvedBase::InPack(entry)) => entry,\n                    Some(ResolvedBase::OutOfPack { end, kind }) => {\n                        base_buffer_size = Some(end);\n                        object_kind = Some(kind);\n                        break;\n                    }\n                    None => return Err(Error::DeltaBaseUnresolved(base_id)),\n                },\n                _ => unreachable!(\"cursor.is_delta() only allows deltas here\"),\n            };\n        }\n\n        // This can happen if the cache held the first entry itself\n        // We will just treat it as an object then, even though it's technically incorrect.\n        if chain.is_empty() {\n            return Ok(Outcome::from_object_entry(\n                object_kind.expect(\"object kind as set by cache\"),\n                &first_entry,\n                consumed_input.expect(\"consumed bytes as set by cache\"),\n            ));\n        }\n\n        // First pass will decompress all delta data and keep it in our output buffer\n        // [<possibly resolved base object>]<delta-1..delta-n>...\n        // so that we can find the biggest result size.\n        let total_delta_data_size: usize = total_delta_data_size.try_into().map_err(|_| Error::OutOfMemory)?;\n\n        let chain_len = chain.len();\n        let actual_base_size = match base_buffer_size {\n            Some(size) => size,\n            None => self.decoded_object_size(cursor.decompressed_size)?,\n        };\n        let (first_buffer_end, second_buffer_end) = {\n            let delta_start = base_buffer_size.unwrap_or(0);\n","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-pack/src/data/file/decode/entry.rs#L279-L315","documentation":"A `expect()` panic in `resolve_deltas`. When the delta chain is empty because the delta cache already held the first entry itself, the code treats the cached entry as a full object and expects `object_kind` to have been recorded by the cache. If `object_kind` is `None` here, the cache returned a chain result without a kind, violating the cache contract — a bug in gix-pack's delta cache interaction.","triggerScenarios":"Calling `decode_entry` (which routes to `resolve_deltas`) on a delta entry whose base object is served entirely from a delta cache that stored the first entry's header and data but (hypothetically) not its kind.","commonSituations":"Heavy delta-cache usage (e.g. `gix_pack::cache::delta` enabled) while decoding many pack entries; library development or fuzzing of the cache/decoder boundary.","solutions":["Update gix-pack; the cache is documented to always set the object kind","Disable or reconfigure the delta-from-state cache as a workaround (e.g. use `cache::Never`)","Reproduce with the pack file and report upstream"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| pack.decode_entry(id, &mut out, ...)));\nif result.is_err() { eprintln!(\"internal panic in delta resolution\"); }","preventionTips":["Use the stock delta cache implementations (`cache::Never`, `cache::Memory`)","Keep all gix-* crates at matching versions","Avoid custom `FromEntries` cache implementations unless thoroughly tested"],"tags":["rust","panic","internal-invariant","gix-pack","delta-cache"],"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"}