tursodatabase/turso · error · anyhow::Error
payload start out of bounds on page
Error message
payload start out of bounds on page {root_page} What it means
The generator reads the raw bytes of a database page to locate the first record's payload, and validates that the computed payload offset lies within the page bytes. If the offset is beyond the page size, the fixture's expected page layout does not match the actual file, so it refuses to patch and reports the offending root page.
Solutions
- Verify the `root_page` matches the table's actual root page in the current schema.
- Ensure the `page_size` argument matches the database's PRAGMA page_size.
- Confirm the page is a table b-tree leaf (0x0D) containing the first row before patching.
Example fix
// before let root_page = 2; // stale after schema change // after let root_page = db_first_table_root_page(&db_path, "t")?; // look up dynamically
Defensive patterns
Strategy: validation
Validate before calling
let page = read_page(&db_path, root_page, page_size)?;
assert_eq!(page[0], 0x0D, "page {root_page} must be a table leaf");
assert!(payload_start < page.len(), "payload_start {payload_start} out of bounds"); Prevention
- Look up root pages from the schema rather than hardcoding
- Pass page_size from PRAGMA page_size, not a constant
- Re-derive root_page after any schema change
When it happens
Trigger: `patch_first_row_serial_type` computes `payload_start` from the page's cell pointer and cell header, and it exceeds `bytes.len()` — usually because the wrong `root_page` or `page_size` was passed, or the page is not a table leaf page.
Common situations: Fixture schema changed (row moved to a different root page), wrong page_size argument, or pointing the patcher at an interior/overflow page instead of a leaf containing the first row.
Related errors
- record header out of bounds on page
- record has no column
- serial types and do not store the same number of bytes
- unexpected serial type
- unknown integrity fixture path
AI-assisted analysis of tursodatabase/turso@8d4a589f8d (2026-09-20).
Data as JSON: /api/errors/5a98d67be8e5056a.
Report an issue: GitHub.
Appendix: source
Thrown at testing/sqltest/src/generator/mod.rs:1070
let first_cell_ptr =
u16::from_be_bytes([bytes[ptr_array_start], bytes[ptr_array_start + 1]]) as usize;
let cell_start = page_start + first_cell_ptr;
anyhow::ensure!(
cell_start < bytes.len(),
"cell pointer out of bounds on page {root_page}"
);
let (_, payload_varint_len) = parse_sqlite_varint(&bytes, cell_start)?;
let (_, rowid_varint_len) = parse_sqlite_varint(&bytes, cell_start + payload_varint_len)?;
let payload_start = cell_start + payload_varint_len + rowid_varint_len;
anyhow::ensure!(
payload_start < bytes.len(),
"payload start out of bounds on page {root_page}"
);
let (header_size, header_size_varint_len) = parse_sqlite_varint(&bytes, payload_start)?;
let header_end = payload_start + header_size as usize;
anyhow::ensure!(
header_end <= bytes.len(),
"record header out of bounds on page {root_page}"
);
let mut serial_offset = payload_start + header_size_varint_len;
for _ in 0..patch.column_index {
let (_, serial_len) = parse_sqlite_varint(&bytes, serial_offset)?;
serial_offset += serial_len;
}
anyhow::ensure!(
serial_offset < header_end,
"record has no column {} on page {root_page}",
patch.column_index
);
anyhow::ensure!(
bytes[serial_offset] == patch.expected_serial_type,
"unexpected serial type {} for column {} of the fixture row, expected {}",
bytes[serial_offset],View on GitHub (pinned to 8d4a589f8d)