GitoxideLabs/gitoxide · warning

at least one decompressed delta object

Error message

at least one decompressed delta object

What it means

A `expect()` panic asserting `consumed_input` is present after resolving deltas, so the resolved object can be put into the delta cache together with the number of input bytes it consumed. If the first (base) delta was decompressed, consumed bytes are always recorded; `None` indicates a broken internal state.

Solutions

  1. Update gix-pack
  2. Avoid patching the first-pass decompress loop without preserving consumed_input assignment
  3. Report upstream with a reproducer if ever hit
Defensive patterns

Strategy: try-catch

Try / catch

let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| pack.decode_entry(id, &mut out, ...)));
if r.is_err() { eprintln!("consumed-input invariant violated"); }

Prevention

When it happens

Trigger: Same path as errorIndex 464: `decode_entry` -> `resolve_deltas` finishing with at least one decompressed delta but missing consumption bookkeeping — only via a code defect.

Common situations: Unreachable in normal use; observed in gix-pack development or when altering the first-pass decompression loop.

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/0f3c5011f35d3b2b. Report an issue: GitHub.

Appendix: source

Thrown at gix-pack/src/data/file/decode/entry.rs:453

        let last_result_size = last_result_size.expect("at least one delta chain item");
        // uneven chains leave the target buffer after the source buffer
        // FIXME(Performance) If delta-chains are uneven, we know we will have to copy bytes over here
        //      Instead we could use a different start buffer, to naturally end up with the result in the
        //      right one.
        //      However, this is a bit more complicated than just that - you have to deal with the base
        //      object, which should also be placed in the second buffer right away. You don't have that
        //      control/knowledge for out-of-pack bases, so this is a special case to deal with, too.
        //      Maybe these invariants can be represented in the type system though.
        if chain_len % 2 == 1 {
            // this seems inverted, but remember: we swapped the buffers on the last iteration
            target_buf[..last_result_size].copy_from_slice(&source_buf[..last_result_size]);
        }
        debug_assert!(out.len() >= last_result_size);
        out.truncate(last_result_size);

        let object_kind = object_kind.expect("a base object as root of any delta chain that we are here to resolve");
        let consumed_input = consumed_input.expect("at least one decompressed delta object");
        cache.put(
            self.id,
            first_entry.data_offset,
            out.as_slice(),
            object_kind,
            consumed_input,
        );
        Ok(Outcome {
            kind: object_kind,
            // technically depending on the cache, the chain size is not correct as it might
            // have been cut short by a cache hit. The caller must deactivate the cache to get
            // actual results
            num_deltas: chain_len as u32,
            decompressed_size: first_entry.decompressed_size,
            compressed_size: consumed_input,
            object_size: last_result_size as u64,
        })
    }

View on GitHub (pinned to e73179060b)