{"record":{"id":"6b0a5f37bea682fc","repo":"quickwit-oss/quickwit","slug":"split-footer-starts-after-its-trailer","errorCode":null,"errorMessage":"split footer starts after its trailer","messagePattern":"split footer starts after its trailer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-storage/src/bundle_storage.rs","lineNumber":258,"sourceCode":"    Ok(footer_start..split_len)\n}\n\nfn locate_split_footer_range_in_tail(\n    split_len: u64,\n    tail_bytes: &[u8],\n) -> anyhow::Result<FooterLocation> {\n    // Legacy split layout:\n    // [body][bundle metadata][metadata len][hotcache][hotcache len]\n    ensure!(\n        tail_bytes.len() as u64 <= split_len,\n        \"split tail is longer than the split itself\"\n    );\n    let trailer_start = tail_bytes\n        .len()\n        .checked_sub(SPLIT_FOOTER_TRAILER_NUM_BYTES)\n        .context(\"split tail is too short to contain a footer trailer\")?;\n    if let Some(footer_start) = deserialize_split_footer_trailer(&tail_bytes[trailer_start..])? {\n        ensure!(\n            footer_start <= split_len - SPLIT_FOOTER_TRAILER_NUM_BYTES as u64,\n            \"split footer starts after its trailer\"\n        );\n        return Ok(FooterLocation::Located(footer_start..split_len));\n    }\n\n    let hotcache_len =\n        u32::from_le_bytes(tail_bytes[tail_bytes.len() - HOTCACHE_LEN_NUM_BYTES..].try_into()?)\n            as u64;\n    let bundle_metadata_len_end = split_len\n        .checked_sub(HOTCACHE_LEN_NUM_BYTES as u64)\n        .and_then(|offset| offset.checked_sub(hotcache_len))\n        .context(\"split footer exceeds split length\")?;\n    let bundle_metadata_len_start = bundle_metadata_len_end\n        .checked_sub(BUNDLE_METADATA_LEN_NUM_BYTES as u64)\n        .context(\"split footer exceeds split length\")?;\n    let bundle_metadata_len_range = bundle_metadata_len_start..bundle_metadata_len_end;\n    let tail_start = split_len - tail_bytes.len() as u64;","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-storage/src/bundle_storage.rs#L240-L276","documentation":"When a modern split footer trailer is found, the footer start offset it records must fall at or before the trailer's position (split_len minus the trailer size). A footer start beyond the trailer means the trailer's offset is corrupt or the split layout is inconsistent, so the library refuses to compute the footer range.","triggerScenarios":"Calling `locate_split_footer_range` / `fetch_split_tail` on a split whose trailer's `footer_start_inclusive` value exceeds `split_len - SPLIT_FOOTER_TRAILER_NUM_BYTES`, e.g. corrupted trailer bytes or a trailer from a longer prior version of the file.","commonSituations":"Split files partially overwritten (trailer kept, body changed or truncated); corrupted bytes in the tail; in-place object edits that invalidated the recorded footer offset.","solutions":["Re-upload or re-index the split to regenerate a consistent footer trailer.","Verify the split object's integrity against its checksum; restore from source if corrupted.","Check for processes modifying split files in place and prevent such overwrites."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match locate_split_footer_range(split, &storage).await {\n    Ok(f) => f,\n    Err(e) if e.to_string().contains(\"footer starts after its trailer\") => {\n        // split tail is corrupt: re-index or re-upload the split\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Treat split files in object storage as immutable; always replace with new objects.","Verify checksums of tail bytes when copying or backing up splits.","Alert on any object-store write operations targeting existing split paths."],"tags":["storage","split-footer","corruption"],"backgroundTag":"internal-invariant-violation","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}