{"record":{"id":"3d716728c597f39b","repo":"GitoxideLabs/gitoxide","slug":"parse-validation","errorCode":null,"errorMessage":"parse validation","messagePattern":"parse validation","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gix-ref/src/store/file/log/line.rs","lineNumber":54,"sourceCode":"            write!(out, \"{} {} \", self.previous_oid, self.new_oid)?;\n            self.signature.write_to(out)?;\n            writeln!(out, \"\\t{}\", check_newlines(self.message.as_ref())?)\n        }\n    }\n\n    fn check_newlines(input: &BStr) -> Result<&BStr, Error> {\n        if input.find_byte(b'\\n').is_some() {\n            return Err(Error::IllegalCharacter);\n        }\n        Ok(input)\n    }\n}\n\nimpl LineRef<'_> {\n    /// The previous object id of the ref. It will be a null hash if there was no previous id as\n    /// this ref is being created.\n    pub fn previous_oid(&self) -> ObjectId {\n        ObjectId::from_hex(self.previous_oid).expect(\"parse validation\")\n    }\n    /// The new object id of the ref, or a null hash if it is removed.\n    pub fn new_oid(&self) -> ObjectId {\n        ObjectId::from_hex(self.new_oid).expect(\"parse validation\")\n    }\n}\n\nimpl<'a> From<LineRef<'a>> for Line {\n    fn from(v: LineRef<'a>) -> Self {\n        Line {\n            previous_oid: v.previous_oid(),\n            new_oid: v.new_oid(),\n            signature: v.signature.into(),\n            message: v.message.into(),\n        }\n    }\n}\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-ref/src/store/file/log/line.rs#L36-L72","documentation":"A Rust `expect()` panic in `LineRef::previous_oid()` (gix-ref/store/file/log/line.rs). Reflog lines store the old object id as fixed-width hex; the line parser (`LineRef::from_bytes`) already verified the hex digits and length before constructing `LineRef`, so `ObjectId::from_hex` must succeed. A panic means hex bytes reached this accessor that the parser never validated — i.e. the `LineRef` was built through `from_bytes`-bypassing paths or on data with a hash length mismatch.","triggerScenarios":"Calling `previous_oid()` on a `LineRef` whose `previous_oid` field came from bytes not parsed by `LineRef::from_bytes` (e.g. constructed directly/unsafely), or parsing lines with a hash kind shorter/longer than the hex actually present.","commonSituations":"Hand-editing or synthesizing reflog entries; parsing reflog files written for a different hash algorithm (SHA-256 vs SHA-1); wrapping raw byte slices as `LineRef` in tests or FFI.","solutions":["Only obtain `LineRef` values from `LineRef::from_bytes`/library parsers; never construct the field directly.","Ensure the reflog belongs to a repository with the hash kind you expect; do not mix SHA-1 and SHA-256 reflogs.","Sanitize or regenerate corrupted reflog lines (restore from a healthy clone or delete the corrupt log file).","Report upstream if library-parsed lines panic — internal invariant violation."],"exampleFix":"// before\nlet line = LineRef { previous_oid: b\"zzzz\".as_ref().into(), .. };\nline.previous_oid(); // panics\n// after\nlet line = LineRef::from_bytes(raw_log_line)?; // validates hex first\nlet old_id = line.previous_oid();","handlingStrategy":"validation","validationCode":"// ensure line came from the parser before reading ids\nlet line = gix_ref::store::file::log::LineRef::from_bytes(raw)?; // validates hex","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only use LineRef produced by from_bytes/owned Line conversion","Match hash kind to the reflog's repository","Never hand-edit reflog files"],"tags":["rust","panic","reflog","hex-decoding"],"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-15T23:17:13.987Z"}