{"record":{"id":"d9d7828b70f42632","repo":"GitoxideLabs/gitoxide","slug":"bug-pack-now-is-smaller-than-all-previously-seen","errorCode":null,"errorMessage":"BUG: pack now is smaller than all previously seen entries","messagePattern":"BUG: pack now is smaller than all previously seen entries","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-pack/src/cache/delta/tree.rs","lineNumber":128,"sourceCode":"                //  - We are draining from future_child_offsets and adding to children, keeping things the same.\n                //  - We can rely on the `future_child_offsets` invariant to be sure that `children` is\n                //    not getting any indices that are already in use in `children` elsewhere\n                //  - The indices are in bounds for child_items since they were in bounds for future_child_offsets,\n                //    we can carry over the invariant.\n                if let Ok(i) = self.child_items.binary_search_by_key(&parent_offset, |i| i.offset) {\n                    self.child_items[i].children.push(child_index as u32);\n                } else if let Ok(i) = self.root_items.binary_search_by_key(&parent_offset, |i| i.offset) {\n                    self.root_items[i].children.push(child_index as u32);\n                } else {\n                    return Err(traverse::Error::OutOfPackRefDelta {\n                        base_pack_offset: parent_offset,\n                    });\n                }\n            }\n        }\n\n        self.assert_is_incrementing_and_update_next_offset(pack_entries_end)\n            .expect(\"BUG: pack now is smaller than all previously seen entries\");\n        Ok(())\n    }\n\n    /// Add a new root node, one that only has children but is not a child itself, at the given pack `offset` and associate\n    /// custom `data` with it.\n    pub(crate) fn add_root(&mut self, offset: crate::data::Offset, data: T) -> Result<(), Error> {\n        self.assert_is_incrementing_and_update_next_offset(offset)?;\n        self.last_seen = NodeKind::Root.into();\n        self.root_items.push(Item {\n            offset,\n            next_offset: 0,\n            data,\n            // SAFETY INVARIANT upheld: there are no children\n            children: Default::default(),\n        });\n        Ok(())\n    }\n","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-pack/src/cache/delta/tree.rs#L110-L146","documentation":"The delta-tree cache used during pack traversal tracks pack entry offsets monotonically. `set_pack_entries_end_and_resolve_ref_offsets` asserts the new pack end offset is not smaller than all previously seen entries via `assert_is_incrementing_and_update_next_offset`. The panic signals a corrupted pack file where an entry's offset runs backwards, breaking the tree's invariants.","triggerScenarios":"Running `traverse()` (e.g. pack verification or index writing via `gix_pack::data::File::verify_checksum`/`Bundle::traverse`) over a pack file whose entries are not sorted by ascending pack offset, typically due to pack corruption.","commonSituations":"Verifying or indexing corrupted/downloaded packs; interrupted pack transfers; disk corruption; manually concatenated pack files.","solutions":["Re-download or re-clone the repository to obtain a fresh pack","Run `git fsck --full` / `gix --verbose pack verify` to confirm corruption","Delete the local objects directory content and re-fetch (`git fetch --refetch` or fresh clone)"],"exampleFix":"// before (caller assumes pack is intact)\nbundle.traverse(...)?;\n// after\n// validate pack integrity first; a corrupted pack must be re-fetched, not patched\nif let Err(e) = bundle.traverse(...) { eprintln!(\"pack corrupt: {e}; re-fetch required\"); }","handlingStrategy":"validation","validationCode":"// check pack integrity before traversal\nrun gitoxide/gix pack verify (or `git fsck --full`) before indexing untrusted packs","typeGuard":null,"tryCatchPattern":"let outcome = std::panic::catch_unwind(|| bundle.traverse(...));\nmatch outcome { Err(_) => eprintln!(\"pack structurally corrupt - re-fetch required\"), Ok(r) => r? }","preventionTips":["Verify pack checksums before traversal on untrusted inputs","Re-download corrupted packs instead of retrying","Ensure entries are visited in ascending pack-offset order when calling the cache directly"],"tags":["rust","panic","pack","corruption","delta"],"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-16T04:17:20.429Z"}