{"record":{"id":"c5f0184b1bbe83d0","repo":"GitoxideLabs/gitoxide","slug":"bug-hunks-are-never-empty-c5f018","errorCode":null,"errorMessage":"BUG: hunks are never empty","messagePattern":"BUG: hunks are never empty","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-blame/src/types.rs","lineNumber":391,"sourceCode":"        range_in_blamed_file: Range<u32>,\n        range_in_source_file: Range<u32>,\n        commit_id: ObjectId,\n        source_file_name: Option<BString>,\n    ) -> Self {\n        debug_assert!(\n            range_in_blamed_file.end > range_in_blamed_file.start,\n            \"{range_in_blamed_file:?}\"\n        );\n        debug_assert!(\n            range_in_source_file.end > range_in_source_file.start,\n            \"{range_in_source_file:?}\"\n        );\n        debug_assert_eq!(range_in_source_file.len(), range_in_blamed_file.len());\n\n        Self {\n            start_in_blamed_file: range_in_blamed_file.start,\n            start_in_source_file: range_in_source_file.start,\n            len: NonZeroU32::new(range_in_blamed_file.len() as u32).expect(\"BUG: hunks are never empty\"),\n            commit_id,\n            source_file_name,\n        }\n    }\n}\n\nimpl BlameEntry {\n    /// Return the range of tokens this entry spans in the *Blamed File*.\n    pub fn range_in_blamed_file(&self) -> Range<usize> {\n        let start = self.start_in_blamed_file as usize;\n        start..start + self.len.get() as usize\n    }\n    /// Return the range of tokens this entry spans in the *Source File*.\n    pub fn range_in_source_file(&self) -> Range<usize> {\n        let start = self.start_in_source_file as usize;\n        start..start + self.len.get() as usize\n    }\n}","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-blame/src/types.rs#L373-L409","documentation":"Same invariant as force_non_zero: when constructing a Hunk, the library expects range_in_blamed_file to have non-zero length, because a blame hunk by definition covers at least one line. A zero-length range at construction time panics via expect instead of returning an error.","triggerScenarios":"Hunk::new (public constructor) called with a range_in_blamed_file whose len() is 0 — e.g. empty or start==end ranges passed by callers or produced by a faulty diff.","commonSituations":"Users or internal code constructing hunks from empty line ranges, typically after a diff computed no lines for a region or after off-by-one range math.","solutions":["Ensure ranges passed to Hunk::new contain at least one line before calling","Validate range length at the call site and skip empty ranges","Return a Result/Option from Hunk::new instead of panicking if empty ranges are legitimate in your use case","Add a debug assertion or validation upstream where ranges are computed"],"exampleFix":"// before\nlet hunk = Hunk::new(range_in_blamed_file, range_in_source_file, commit_id, None);\n// after\nassert!(!range_in_blamed_file.is_empty(), \"hunks must cover at least one line\");\nlet hunk = Hunk::new(range_in_blamed_file, range_in_source_file, commit_id, None);","handlingStrategy":"validation","validationCode":"if range_in_blamed_file.is_empty() {\n    return Err(anyhow!(\"hunk range must contain at least one line\"));\n}","typeGuard":"fn non_empty_range(r: &Range<usize>) -> bool { !r.is_empty() }","tryCatchPattern":null,"preventionTips":["Never construct Hunk from empty ranges; skip them instead","Check diff computation for zero-length regions before mapping to hunks","Add unit tests for range math off-by-ones","Validate line ranges (start < end) before calling public constructors"],"tags":["panic","invariant","blame","hunk"],"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"}