{"record":{"id":"b930861a288e160e","repo":"quickwit-oss/quickwit","slug":"hot-directory-metadata-s-magic-number-does-not-mat","errorCode":null,"errorMessage":"hot directory metadata's magic number does not match","messagePattern":"hot directory metadata's magic number does not match","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-storage/src/versioned_component.rs","lineNumber":100,"sourceCode":"///\n/// (This function is not part of the trait to make it private.)\nfn try_read_version<V: VersionedComponent>(bytes: &mut OwnedBytes) -> anyhow::Result<V> {\n    let mut header_bytes: [u8; 8] = [0u8; 8];\n    bytes\n        .read_exact(&mut header_bytes[..])\n        .with_context(|| format!(\"failed to read header for {}\", V::component_name()))?;\n    try_deserialize_from_bytes::<V>(header_bytes)\n}\n\n/// Deserialize the header from 8 bytes.\n/// An error is returned if the magic number does not match,\n/// or if the version is unsupported.\n///\n/// (This function is not part of the trait to make it private.)\nfn try_deserialize_from_bytes<V: VersionedComponent>(header_bytes: [u8; 8]) -> anyhow::Result<V> {\n    let magic_number = u32::from_le_bytes(header_bytes[0..4].try_into().unwrap());\n    if magic_number != V::MAGIC_NUMBER {\n        anyhow::bail!(\"hot directory metadata's magic number does not match\");\n    }\n    let version_code: u32 = u32::from_le_bytes(header_bytes[4..8].try_into().unwrap());\n    V::try_from_version_code_impl(version_code).with_context(|| {\n        format!(\n            \"version code {} is not supported for {}\",\n            version_code,\n            V::component_name()\n        )\n    })\n}\n\n#[cfg(test)]\nmod tests {\n    use tantivy::directory::OwnedBytes;\n\n    use crate::VersionedComponent;\n\n    #[derive(Copy, Clone, Default)]","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-storage/src/versioned_component.rs#L82-L118","documentation":"Versioned components (e.g. hot directory metadata) persist an 8-byte header: a 4-byte LE magic number followed by a version code. During deserialization, if the first 4 bytes don't equal the component's MAGIC_NUMBER, the bytes are not a file this reader understands and it bails before even checking the version. Guards against reading unrelated or corrupted files.","triggerScenarios":"Opening a hotcache/hot-directory metadata file whose header was corrupted, was written by a different component, or is a truncated/zeroed file so the magic number check fails.","commonSituations":"Disk corruption or partial writes on the hotcache directory; pointing a reader at the wrong file; manually copied/moved files between incompatible quickwit versions or storage layouts.","solutions":["Delete the corrupted hotcache/metadata file and let quickwit rebuild it from the split.","Verify the file was produced by the same quickwit version writing the same component format.","Check storage/disk health for corruption if this recurs."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"let mut header = [0u8; 8];\nfile.read_exact(&mut header)?;\nlet magic = u32::from_le_bytes(header[0..4].try_into()?);\nif magic != EXPECTED_MAGIC { /* rebuild hotcache instead of loading */ }","typeGuard":null,"tryCatchPattern":"match try_deserialize(bytes) {\n    Err(e) if e.to_string().contains(\"magic number\") => rebuild_metadata(),\n    other => other?,\n}","preventionTips":["Never hand-edit or partially copy hotcache metadata files.","Rebuild hotcache after crashes or unclean shutdowns."],"tags":["corruption","magic-number","deserialization"],"backgroundTag":"invalid-argument-format","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}