GitoxideLabs/gitoxide · warning
always valid for non-refs
Error message
always valid for non-refs
What it means
A `expect()` panic in the public pack entry header decoding (`Outcome` construction). The loop returns an `Outcome` only for non-delta headers (Tree/Blob/Commit/Tag), and `as_kind()` is `Some` exactly for those, so the conversion cannot fail. Failure would mean a delta header reached a non-delta branch.
Solutions
- Keep all gix-* crates at the same version (use the workspace-provided version pins)
- Update gix-pack if a header-decoding fix was released
- Report a bug with the offending pack bytes
Defensive patterns
Strategy: try-catch
Try / catch
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| header.to_outcome()));
if r.is_err() { eprintln!("pack header invariant violated"); } Prevention
- Do not mutate pack entry bytes before header decoding
- Keep all gix crates at the same workspace version
- Report mutated-header fuzz crashes upstream
When it happens
Trigger: Calling pack entry header decoding (e.g. `gix_pack::data::entry::Header` Outcome computation) — the panic fires only if header matching logic regresses, e.g. after a version change or code modification.
Common situations: gix-pack development, fuzzing of pack entry headers with mutated bytes, or mismatched gix crate versions.
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
- object kind as set by cache
- consumed bytes as set by cache
- at least one delta chain item
- a base object as root of any delta chain that we are here…
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/4c543dbf0db91792.
Report an issue: GitHub.
Appendix: source
Thrown at gix-pack/src/data/file/decode/header.rs:66
/// For delta entries, this only probes the initial delta header bytes to determine the result
/// object size. It can reject streams that end or overflow within that probe, but it does not
/// fully validate that the compressed stream produces exactly the decompressed size declared in
/// the pack entry header. Use [`File::decode_entry()`][crate::data::File::decode_entry()] when
/// callers need that full validation.
pub fn decode_header(
&self,
mut entry: data::Entry,
inflate: &mut gix_zlib::Inflate,
resolve: &dyn Fn(&gix_hash::oid) -> Option<ResolvedBase>,
) -> Result<Outcome, Error> {
use crate::data::entry::Header::*;
let mut num_deltas = 0;
let mut first_delta_decompressed_size = None::<u64>;
loop {
match entry.header {
Tree | Blob | Commit | Tag => {
return Ok(Outcome {
kind: entry.header.as_kind().expect("always valid for non-refs"),
object_size: first_delta_decompressed_size.unwrap_or(entry.decompressed_size),
num_deltas,
});
}
OfsDelta { base_distance } => {
num_deltas += 1;
if first_delta_decompressed_size.is_none() {
first_delta_decompressed_size = Some(self.decode_delta_object_size(inflate, &entry)?);
}
entry = self.entry(entry.checked_base_pack_offset(base_distance).ok_or(
crate::data::entry::decode::Error::Corrupt {
message: "an ofs-delta base distance pointing before pack start",
},
)?)?;
}
RefDelta { base_id } => {
num_deltas += 1;
if first_delta_decompressed_size.is_none() {View on GitHub (pinned to e73179060b)