{"record":{"id":"bb1ba6d765b7d818","repo":"tursodatabase/turso","slug":"mvcc-logical-log-extension-block-missing-flag-at-o","errorCode":null,"errorMessage":"MVCC logical log extension block missing flag at offset {offset}","messagePattern":"MVCC logical log extension block missing flag at offset (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"cli/sync_server.rs","lineNumber":1068,"sourceCode":"    let payload_size = usize::try_from(read_u64_le(log, offset + 4)?)\n        .map_err(|_| anyhow!(\"MVCC logical log payload size overflows usize\"))?;\n    let extension_size = if has_extension_header {\n        let extension_size = usize::try_from(read_u64_le(log, offset + 24)?)\n            .map_err(|_| anyhow!(\"MVCC logical log extension size overflows usize\"))?;\n        let extension_record_count = read_u32_le(log, offset + 32)?;\n        let frame_flags = read_u32_le(log, offset + 36)?;\n        if frame_flags & !MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK != 0 {\n            return Err(anyhow!(\n                \"unsupported MVCC logical log frame flags at offset {offset}: {frame_flags:#x}\"\n            ));\n        }\n        if extension_size == 0 && extension_record_count != 0 {\n            return Err(anyhow!(\n                \"MVCC logical log extension record count without extension block at offset {offset}\"\n            ));\n        }\n        if extension_size > 0 && frame_flags & MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK == 0 {\n            return Err(anyhow!(\n                \"MVCC logical log extension block missing flag at offset {offset}\"\n            ));\n        }\n        extension_size\n    } else {\n        0\n    };\n    let trailer_start = offset\n        .checked_add(header_size)\n        .and_then(|value| value.checked_add(payload_size))\n        .and_then(|value| value.checked_add(extension_size))\n        .ok_or_else(|| anyhow!(\"MVCC logical log frame offset overflow\"))?;\n    let frame_end = trailer_start\n        .checked_add(MVCC_TX_TRAILER_SIZE)\n        .ok_or_else(|| anyhow!(\"MVCC logical log frame end overflow\"))?;\n    if frame_end > log.len() {\n        return Ok(None);\n    }","sourceCodeStart":1050,"sourceCodeEnd":1086,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/cli/sync_server.rs#L1050-L1086","documentation":"The inverse consistency rule: extension_size > 0 requires MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK set in the flags word at offset +36. A non-empty extension block that the flags word does not announce is self-contradictory, and the reader cannot trust the trailer offset derived from the extension size. The scan rejects the frame outright.","triggerScenarios":"Scanning an extension frame with a nonzero extension size whose flags word lacks MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK — a producer that writes the block but forgets to set the flag, or corruption that cleared the flag bit while leaving the size intact.","commonSituations":"Hand-written frame builders in tests or tooling; tools that rewrite or splice frames without updating flags; bit flips confined to the flags word.","solutions":["Re-pull the log; the frame header contradicts itself and cannot be parsed safely.","If producing frames, always set MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK when extension_size > 0.","Audit tools that rewrite frames to keep flags and sizes in sync."],"exampleFix":"// before\nwrite_frame_header(&mut out, payload, extension_bytes, record_count, 0); // flag missing\n\n// after\nlet flags = if extension_bytes.is_empty() { 0 } else { MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK };\nwrite_frame_header(&mut out, payload, extension_bytes, record_count, flags);","handlingStrategy":"try-catch","validationCode":"fn extension_flag_matches_size(log: &[u8], offset: usize) -> bool {\n    let size = log.get(offset + 24..offset + 32)\n        .map(|b| u64::from_le_bytes(b.try_into().unwrap()))\n        .unwrap_or(0);\n    let flags = log.get(offset + 36..offset + 40)\n        .map(|b| u32::from_le_bytes(b.try_into().unwrap()))\n        .unwrap_or(0);\n    (size > 0) == (flags & MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK != 0)\n}","typeGuard":"fn extension_flag_matches_size(log: &[u8], offset: usize) -> bool {\n    let size = log.get(offset + 24..offset + 32)\n        .map(|b| u64::from_le_bytes(b.try_into().unwrap()))\n        .unwrap_or(0);\n    let flags = log.get(offset + 36..offset + 40)\n        .map(|b| u32::from_le_bytes(b.try_into().unwrap()))\n        .unwrap_or(0);\n    (size > 0) == (flags & MVCC_TX_FRAME_FLAG_HAS_EXTENSION_BLOCK != 0)\n}","tryCatchPattern":"match scan_mvcc_log(&log) {\n    Ok(snapshot) => { /* serve deltas */ }\n    Err(err) if err.to_string().contains(\"extension block missing flag\") => {\n        // flags contradict the size field: re-pull the log\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Derive the flag from the block size in producers: set it iff extension_size > 0.","Never rewrite frame bytes without recomputing both flags and sizes.","Keep test frame builders aligned with the validator rules."],"tags":["mvcc","turso","sync","file-format","consistency"],"backgroundTag":"file-format-validation-failed","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}