{"record":{"id":"c41057d2d5371eb9","repo":"tursodatabase/turso","slug":"record-header-out-of-bounds-on-page-root-page","errorCode":null,"errorMessage":"record header out of bounds on page {root_page}","messagePattern":"record header out of bounds on page (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"testing/sqltest/src/generator/mod.rs","lineNumber":1080,"sourceCode":"    let payload_start = cell_start + payload_varint_len + rowid_varint_len;\n    anyhow::ensure!(\n        payload_start < bytes.len(),\n        \"payload start out of bounds on page {root_page}\"\n    );\n\n    let (header_size, header_size_varint_len) = parse_sqlite_varint(&bytes, payload_start)?;\n    let header_end = payload_start + header_size as usize;\n    anyhow::ensure!(\n        header_end <= bytes.len(),\n        \"record header out of bounds on page {root_page}\"\n    );\n\n    let mut serial_offset = payload_start + header_size_varint_len;\n    for _ in 0..patch.column_index {\n        let (_, serial_len) = parse_sqlite_varint(&bytes, serial_offset)?;\n        serial_offset += serial_len;\n    }\n    anyhow::ensure!(\n        serial_offset < header_end,\n        \"record has no column {} on page {root_page}\",\n        patch.column_index\n    );\n    anyhow::ensure!(\n        bytes[serial_offset] == patch.expected_serial_type,\n        \"unexpected serial type {} for column {} of the fixture row, expected {}\",\n        bytes[serial_offset],\n        patch.column_index,\n        patch.expected_serial_type\n    );\n    bytes[serial_offset] = patch.new_serial_type;\n\n    std::fs::write(db_path, bytes)\n        .with_context(|| format!(\"failed to write fixture '{}'\", db_path.display()))?;\n    Ok(())\n}\n","sourceCodeStart":1062,"sourceCodeEnd":1098,"githubUrl":"https://github.com/tursodatabase/turso/blob/8d4a589f8d13ac184700d2a8f724f27e1995be3b/testing/sqltest/src/generator/mod.rs#L1062-L1098","documentation":"After locating the payload, the generator parses the record header size and checks that the whole header fits inside the page bytes. If `payload_start + header_size` exceeds the page length, the page bytes don't match the expected SQLite record format and patching would read garbage, so it aborts for that root page.","triggerScenarios":"`patch_first_row_serial_type` computes `header_end = payload_start + header_size` from the parsed varint and it exceeds `bytes.len()` — caused by a malformed or non-leaf page, wrong page size, or overflow payload spilling off the page.","commonSituations":"Patching a row whose record spills to overflow pages, wrong page_size passed in, or the target page isn't the table leaf containing the first row.","solutions":["Verify page_size matches the actual database page size.","Ensure the target row's record fits entirely on the leaf page (no overflow).","Re-check that `root_page` points at the table's leaf page containing the first row."],"exampleFix":"// before\nlet page_size = 4096; // db actually uses 512\n// after\nlet page_size = db_page_size(&db_path)?;","handlingStrategy":"validation","validationCode":"let (header_size, _) = parse_sqlite_varint(&page, payload_start)?;\nassert!(payload_start + header_size as usize <= page.len(), \"record header spills past page {root_page}; check page_size and overflow\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only patch records that fit on the leaf page (no overflow)","Confirm page_size matches PRAGMA page_size","Validate page type byte (0x0D) before parsing the record"],"tags":["sqlite","fixture","page-layout","testing"],"backgroundTag":"index-out-of-bounds","analyzedSha":"8d4a589f8d13ac184700d2a8f724f27e1995be3b","analyzedAt":"2026-09-20T13:18:14.658Z","contentChangedAt":"2026-09-20T13:18:14.658Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}