{"record":{"id":"bd2b9409bd22d5d4","repo":"tursodatabase/turso","slug":"serial-types-and-do-not-store-the-same-number-of-bytes","errorCode":null,"errorMessage":"serial types {} and {} do not store the same number of bytes","messagePattern":"serial types (.+?) and (.+?) do not store the same number of bytes","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"testing/sqltest/src/generator/mod.rs","lineNumber":1029,"sourceCode":"    let table_root_page = get_root_page(&conn, \"t\", relative_path).await?;\n\n    drop(conn);\n    drop(db);\n    patch_first_row_serial_type(db_path, page_size, table_root_page, patch)?;\n    remove_db_sidecars(db_path)?;\n    Ok(())\n}\n\n/// Replace the serial type of one column in the first row of a table page. Both\n/// serial types must store the same number of bytes, so that the rest of the\n/// record keeps its place.\nfn patch_first_row_serial_type(\n    db_path: &Path,\n    page_size: usize,\n    root_page: usize,\n    patch: FirstRowSerialTypePatch,\n) -> Result<()> {\n    anyhow::ensure!(\n        sqlite_serial_type_payload_len(u64::from(patch.expected_serial_type))\n            == sqlite_serial_type_payload_len(u64::from(patch.new_serial_type)),\n        \"serial types {} and {} do not store the same number of bytes\",\n        patch.expected_serial_type,\n        patch.new_serial_type\n    );\n\n    let mut bytes = std::fs::read(db_path)\n        .with_context(|| format!(\"failed to read fixture '{}'\", db_path.display()))?;\n    let page_start = (root_page - 1) * page_size;\n    anyhow::ensure!(\n        bytes.len() > page_start + 8,\n        \"fixture too small to patch page {root_page}\"\n    );\n\n    let cell_count = u16::from_be_bytes([bytes[page_start + 3], bytes[page_start + 4]]) as usize;\n    anyhow::ensure!(\n        cell_count >= 1,","sourceCodeStart":1011,"sourceCodeEnd":1047,"githubUrl":"https://github.com/tursodatabase/turso/blob/8d4a589f8d13ac184700d2a8f724f27e1995be3b/testing/sqltest/src/generator/mod.rs#L1011-L1047","documentation":"When the sqltest fixture generator patches the first row's serial type in a raw database page, it requires that the old and new serial types encode the same payload size, because the patch is an in-place byte rewrite that cannot move data. Mismatched sizes would corrupt the record layout, so the generator rejects the patch up front.","triggerScenarios":"Calling `patch_first_row_serial_type` with a `FirstRowSerialTypePatch` whose `expected_serial_type` and `new_serial_type` have different payload lengths (e.g. replacing serial type 1 / int8 with serial type 4 / int32), via `generate_not_null_violation_fixture`, `generate_gencol_not_null_violation_fixture`, or `generate_strict_fixture`.","commonSituations":"Editing fixture definitions and choosing a replacement serial type of a different width, or hand-crafting a corrupt-fixture patch for a new test case.","solutions":["Choose a `new_serial_type` with the same payload length as the original (same-size types: 0/8/9/12/13 are 0 bytes; 1/2/3/4/5/6 differ; 7 is 8 bytes).","Verify with `sqlite_serial_type_payload_len` for both types before patching.","If a different size is truly needed, write a full record rewrite instead of an in-place serial-type patch."],"exampleFix":"// before\npatch.expected_serial_type = 1; // 1 byte\npatch.new_serial_type = 4;      // 4 bytes -> rejected\n// after\npatch.expected_serial_type = 1; // 1 byte\npatch.new_serial_type = 2;      // also 1 byte... use matching sizes, e.g. 1 -> 2\n","handlingStrategy":"validation","validationCode":"use sqlite_serial_type_payload_len;\nassert_eq!(\n    sqlite_serial_type_payload_len(u64::from(patch.expected_serial_type)),\n    sqlite_serial_type_payload_len(u64::from(patch.new_serial_type)),\n    \"patch must replace a serial type with same payload size\"\n);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a table of serial-type payload sizes handy when writing patches","Prefer same-width types (1<->2<->3<->4<->5<->6 differ; group 1|2 with same byte width per size class)","Add the size check to a shared patch-builder helper"],"tags":["sqlite","fixture","validation","testing"],"backgroundTag":"invalid-argument-value","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"}