GitoxideLabs/gitoxide · error
cursor.is_delta() only allows deltas here
Error message
cursor.is_delta() only allows deltas here
What it means
`resolve_deltas` in `gix-pack` decodes a pack entry's delta chain; `cursor.is_delta()` guarantees the match only sees OFS/REF deltas, so the default arm panics. Firing means a non-delta entry kind reached delta resolution — a decoder invariant violation, typically from corrupted in-memory cursor state rather than bad pack data (bad data yields `Error::DeltaBaseUnresolved` instead).
Solutions
- Verify pack integrity (e.g. `git fsck`, `gix repo verify`) if you suspect corruption.
- Report upstream with the pack file and entry that triggered it.
- Update `gix-pack` to the latest version.
- If maintaining, map the default arm to `Error::DeltaBaseUnresolved` or a new decode error instead of panicking.
Example fix
// before
_ => unreachable!("cursor.is_delta() only allows deltas here"),
// after
_ => return Err(Error::DeltaBaseUnresolved(base_id)), Defensive patterns
Strategy: try-catch
Validate before calling
// Check pack integrity before heavy decoding // gix_pack::data::File::verify_checksum(...) or git fsck on the repository
Try / catch
let res = std::panic::catch_unwind(|| file.decode_entry(entry, ...)); // on panic: treat pack as suspect, re-verify or re-clone
Prevention
- Verify pack checksums when consuming untrusted packs
- Keep gix-pack and gix-odb versions aligned
- Report panics with the offending pack file
When it happens
Trigger: Calling `gix_pack::data::File::decode_entry` on an entry whose cursor claims `is_delta()` but whose resolved kind is neither OFS nor REF delta — practically only after pack cache or decoder bugs.
Common situations: Not reachable with well-formed packs; could appear with a corrupted pack file interacting with cache assumptions or a version mismatch in pack decoding code.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- a non-delta entry
- only value and unspecified are possible here
- parent-match assures this
- upper match already assured we only deal with blobs
- fixed size array with three items
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/7d256fd5ca4d8257.
Report an issue: GitHub.
Appendix: source
Thrown at gix-pack/src/data/file/decode/entry.rs:289
use crate::data::entry::Header;
cursor = match cursor.header {
Header::OfsDelta { base_distance } => {
self.entry(cursor.checked_base_pack_offset(base_distance).ok_or(
crate::data::entry::decode::Error::Corrupt {
message: "an ofs-delta base distance pointing before pack start",
},
)?)?
}
Header::RefDelta { base_id } => match resolve(base_id.as_ref(), out) {
Some(ResolvedBase::InPack(entry)) => entry,
Some(ResolvedBase::OutOfPack { end, kind }) => {
base_buffer_size = Some(end);
object_kind = Some(kind);
break;
}
None => return Err(Error::DeltaBaseUnresolved(base_id)),
},
_ => unreachable!("cursor.is_delta() only allows deltas here"),
};
}
// This can happen if the cache held the first entry itself
// We will just treat it as an object then, even though it's technically incorrect.
if chain.is_empty() {
return Ok(Outcome::from_object_entry(
object_kind.expect("object kind as set by cache"),
&first_entry,
consumed_input.expect("consumed bytes as set by cache"),
));
}
// First pass will decompress all delta data and keep it in our output buffer
// [<possibly resolved base object>]<delta-1..delta-n>...
// so that we can find the biggest result size.
let total_delta_data_size: usize = total_delta_data_size.try_into().map_err(|_| Error::OutOfMemory)?;
View on GitHub (pinned to e73179060b)