{"record":{"id":"2ce6a217b83dfa34","repo":"quickwit-oss/quickwit","slug":"data-too-short-len","errorCode":null,"errorMessage":"data too short (len={})","messagePattern":"data too short \\(len=(.+?)\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-directories/src/hot_directory.rs","lineNumber":58,"sourceCode":"    const MAGIC_NUMBER: u32 = 2_557_869_106u32;\n    type Component = HotDirectoryMeta;\n\n    fn to_version_code(self) -> u32 {\n        self as u32\n    }\n\n    fn try_from_version_code_impl(code: u32) -> Option<Self> {\n        match code {\n            1u32 => Some(Self::V1),\n            _ => None,\n        }\n    }\n\n    fn deserialize_impl(&self, bytes: &mut OwnedBytes) -> anyhow::Result<HotDirectoryMeta> {\n        match self {\n            Self::V1 => {\n                if bytes.len() < 4 {\n                    bail!(\"data too short (len={})\", bytes.len());\n                }\n                let len = bytes.read_u32() as usize;\n                let hot_directory_meta = postcard::from_bytes(&bytes.as_slice()[..len])\n                    .context(\"failed to deserialize hot directory meta\")?;\n                bytes.advance(len);\n                Ok(hot_directory_meta)\n            }\n        }\n    }\n\n    fn serialize_impl(component: &Self::Component, output: &mut Vec<u8>) {\n        let buf = postcard::to_stdvec(component).unwrap();\n        output.extend_from_slice(&(buf.len() as u32).to_le_bytes());\n        output.extend_from_slice(&buf[..]);\n    }\n}\n\n#[derive(Serialize, Deserialize)]","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-directories/src/hot_directory.rs#L40-L76","documentation":"HotDirectory caches split footer/metadata in a serialized blob: a 4-byte little-endian length prefix followed by a postcard-serialized `HotDirectoryMeta`. `deserialize_impl` bails with \"data too short\" when fewer than 4 bytes remain, because it cannot even read the length prefix.","triggerScenarios":"Calling `HotDirectory::deserialize`/open with an `OwnedBytes` shorter than 4 bytes — e.g. a truncated or empty hotcache file read from storage, or feeding the deserializer the wrong (non-hotcache) bytes.","commonSituations":"Corrupted or partially uploaded split where the hotcache byte array was truncated; storage returning empty object content on failed read; hotcache written by an incompatible/older writer producing zero-length payload.","solutions":["Re-upload or re-fetch the split: the hotcache blob is truncated, so delete and re-index the affected split.","Verify the bytes passed to deserialize are the hotcache file contents (e.g. `.hotcache`) and not another artifact.","Check storage/network for partial reads; confirm the object's content length matches the manifest."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"fn hotcache_bytes_look_valid(bytes: &[u8]) -> bool { bytes.len() >= 4 }","typeGuard":null,"tryCatchPattern":"match hot_directory::deserialize(bytes) {\n    Ok(meta) => Ok(meta),\n    Err(e) if e.to_string().contains(\"data too short\") => {\n        // treat split as corrupted: fail leaf search for this split and request re-index\n        Err(anyhow::anyhow!(\"corrupt/empty hotcache: {e:#}\"))\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Verify split uploads complete (checksum/length checks against the manifest).","Handle storage partial reads by retrying fetches of the hotcache file.","Alert on zero-length hotcache objects in storage."],"tags":["serialization","hotcache","truncated-data","storage"],"backgroundTag":"checksum-mismatch","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}