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

  1. Verify pack integrity (e.g. `git fsck`, `gix repo verify`) if you suspect corruption.
  2. Report upstream with the pack file and entry that triggered it.
  3. Update `gix-pack` to the latest version.
  4. 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

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


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)