{"record":{"id":"ea143eff220fcd0d","repo":"BoundaryML/baml","slug":"invalid-span-range-start-start-end-end","errorCode":null,"errorMessage":"invalid Span range: start ({start}) > end ({end})","messagePattern":"invalid Span range: start \\((.+?)\\) > end \\((.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"baml_language/crates/baml_base/src/core_types.rs","lineNumber":117,"sourceCode":"    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {\n        BorshSerialize::serialize(&self.file_id, writer)?;\n        let start: u32 = self.range.start().into();\n        let end: u32 = self.range.end().into();\n        BorshSerialize::serialize(&start, writer)?;\n        BorshSerialize::serialize(&end, writer)?;\n        Ok(())\n    }\n}\n\nimpl BorshDeserialize for Span {\n    fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {\n        let file_id = FileId::deserialize_reader(reader)?;\n        let start = u32::deserialize_reader(reader)?;\n        let end = u32::deserialize_reader(reader)?;\n        // `TextRange::new` panics on `end < start`. A malformed envelope\n        // should surface as a clean borsh error rather than a thread crash.\n        if start > end {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidData,\n                format!(\"invalid Span range: start ({start}) > end ({end})\"),\n            ));\n        }\n        Ok(Span {\n            file_id,\n            range: TextRange::new(TextSize::new(start), TextSize::new(end)),\n        })\n    }\n}\n\nimpl Default for Span {\n    /// Creates a sentinel span that doesn't refer to any real file.\n    ///\n    /// Uses `u32::MAX` as the file ID to avoid conflicts with real files.\n    fn default() -> Self {\n        Self::fake()\n    }","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/baml_base/src/core_types.rs#L99-L135","documentation":"A Span (file location range) failed to deserialize because the encoded start offset is greater than the end offset. Spans are (file_id, start, end) triples serialized with borsh; TextRange::new would panic on end < start, so the deserializer converts the malformed envelope into a clean std::io error with ErrorKind::InvalidData instead of crashing the thread. This means the serialized data was corrupt, truncated, or produced by an incompatible writer.","triggerScenarios":"Calling Span::deserialize_reader (e.g. while loading a persisted index, cache, or IPC payload) on bytes where the u32 start field exceeds the u32 end field.","commonSituations":"Stale or hand-edited cache files from an older BAML version with a different serialization layout; byte-order/offset desync when reading a concatenated stream at the wrong position; corrupted incremental-compilation artifacts.","solutions":["Delete the stale cache/index artifact that is being deserialized and regenerate it.","Verify the reader is positioned at the correct offset in the stream so fields are not read shifted (file_id, start, end).","Ensure producer and consumer use the same version of the Span serialization format.","Validate the source data ranges (start <= end) before serializing Spans."],"exampleFix":"// before: blindly trust cached spans\nlet span = Span::deserialize_reader(&mut reader)?;\n// after: tolerate corrupt caches by rebuilding\nlet span = Span::deserialize_reader(&mut reader)\n    .map_err(|e| { fs::remove_file(&cache_path).ok(); e })?;","handlingStrategy":"validation","validationCode":"// validate before serializing / after deserializing\nfn valid_span(start: u32, end: u32) -> bool { start <= end }","typeGuard":"fn is_valid_span(s: &Span) -> bool { s.start <= s.end }","tryCatchPattern":"match Span::deserialize_reader(&mut reader) {\n    Ok(span) => span,\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {\n        // rebuild/regenerate the corrupted artifact\n        regenerate(&path)?\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Validate start <= end before serializing any span.","Never hand-edit binary cache artifacts.","Regenerate caches after upgrading the library version.","Read streams at verified offsets with length-prefixed records."],"tags":["deserialization","corrupt-data","span"],"backgroundTag":"invalid-argument-value","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}