{"record":{"id":"0cb7020e05c527b3","repo":"EpicGames/lore","slug":"level-header-file-is-bytes-expected-expected","errorCode":null,"errorMessage":"level header file is {} bytes, expected {expected}","messagePattern":"level header file is (.+?) bytes, expected (.+?)","errorType":"exception","errorClass":"io::Error (UnexpectedEof)","httpStatus":null,"severity":"error","filePath":"lore-storage/src/local/fan_out.rs","lineNumber":389,"sourceCode":"    {\n        Ok(()) => Ok(()),\n        Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()),\n        Err(err) => Err(err),\n    }\n}\n\n/// Read a level-header file (marker or pending) from an explicit path. Shared format helper;\n/// one backend dispatch covering open, read and close, the file being the header itself.\nasync fn read_level_header_file(path: &Path) -> std::io::Result<Option<usize>> {\n    let bytes = match lore_io::IoDriver::global().read_file_bytes(path).await {\n        Ok(bytes) => bytes,\n        Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),\n        Err(err) => return Err(err),\n    };\n    let mut header = LevelMarkerHeader::new_zeroed();\n    let expected = size_of::<LevelMarkerHeader>();\n    if bytes.len() < expected {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::UnexpectedEof,\n            format!(\n                \"level header file is {} bytes, expected {expected}\",\n                bytes.len()\n            ),\n        ));\n    }\n    header.as_mut_bytes().copy_from_slice(&bytes[..expected]);\n    if header.magic != MARKER_MAGIC {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidData,\n            format!(\n                \"level header file has invalid magic 0x{:08x}, expected 0x{:08x}\",\n                header.magic, MARKER_MAGIC\n            ),\n        ));\n    }\n    if header.version != MARKER_VERSION {","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-storage/src/local/fan_out.rs#L371-L407","documentation":"`read_level_header_file` in lore-storage's fan-out reads a level marker file and expects at least `size_of::<LevelMarkerHeader>()` bytes. If the file is shorter, it returns `UnexpectedEof` with the actual vs expected byte count. (A missing file is tolerated and yields `Ok(None)` — only an existing-but-too-short file errors.) This indicates a truncated or corrupt marker file.","triggerScenarios":"Reading a level marker/pending file (`read_level_marker`, `read_level_pending`) when the header file exists but contains fewer bytes than a zeroed `LevelMarkerHeader` — e.g. a partially written or truncated header.","commonSituations":"Crash or power loss between file creation and header write, disk-full during a header write, manual truncation of store files, or copy tools that truncated the file.","solutions":["Delete the corrupt header file so the level is re-initialized (reads then return Ok(None)).","Restore the file from backup or re-run the operation that was supposed to write the header.","Check free disk space and whether previous writes crashed mid-write; fix the underlying cause before retrying."],"exampleFix":"// before\nlet header = read_level_marker(dir).await?;\n\n// after\nmatch read_level_marker(dir).await {\n    Ok(h) => h,\n    Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {\n        fs::remove_file(header_path).ok(); // re-init level\n        None\n    }\n    Err(e) => return Err(e),\n}","handlingStrategy":"try-catch","validationCode":"if let Ok(meta) = tokio::fs::metadata(&header_path).await {\n    if meta.len() < std::mem::size_of::<LevelMarkerHeader>() as u64 {\n        // header truncated: delete and let the level re-initialize\n    }\n}","typeGuard":null,"tryCatchPattern":"match read_level_marker(dir).await {\n    Ok(h) => h,\n    Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => { remove_corrupt_header(dir)?; None },\n    Err(e) => return Err(e),\n}","preventionTips":["Write headers atomically (temp file + rename) so partial writes never appear.","Watch for crashes/disk-full during store writes.","Periodically validate header sizes in store maintenance code."],"tags":["io","corrupt-file","truncated-file"],"backgroundTag":"file-read-failed","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}