tursodatabase/turso · critical

invalid cell payload

Error message

invalid cell payload

What it means

After building the replacement interior cell payload (4-byte big-endian left-child pointer followed by the key), the parent update parses cell_payload[..4] back into a page number with try_into().expect("invalid cell payload"). The panic fires when the freshly built payload is shorter than 4 bytes, which the builders (child_pointer.to_be_bytes() extension) should never produce.

Source

Thrown at core/storage/btree.rs:6786

                                    )?;
                                }
                            }
                            _ => unreachable!("Expected table leaf cell"),
                        }
                        (cell_payload, leaf_cell_idx)
                    };

                    let leaf_page = self.stack.top_ref();

                    self.pager.add_dirty(page)?;
                    self.pager.add_dirty(leaf_page)?;

                    // Step 2: Replace the cell in the parent (interior) page.
                    {
                        let parent_contents = page.get_contents();
                        let parent_page_id = page.get().id;
                        let left_child_page = u32::from_be_bytes(
                            cell_payload[..4].try_into().expect("invalid cell payload"),
                        );
                        turso_assert!(
                            left_child_page as usize != parent_page_id,
                            "corrupt: current page and left child page are the same",
                            { "left_child_page": left_child_page, "parent_page_id": parent_page_id }
                        );

                        // First, drop the old cell that is being replaced.
                        drop_cell(parent_contents, cell_idx, usable_space)?;
                        // Then, insert the new cell (the predecessor) in its place.
                        insert_into_cell(parent_contents, &cell_payload, cell_idx, usable_space)?;
                    }

                    // Step 3: Delete the predecessor cell from the leaf page.
                    {
                        let leaf_contents = leaf_page.get_contents();
                        drop_cell(leaf_contents, leaf_cell_idx, usable_space)?;
                    }

View on GitHub (pinned to 6c72522679)

Solutions

  1. Report to Turso with the exact DELETE statement and a copy of the database - payload construction cannot legitimately produce <4 bytes
  2. Run PRAGMA integrity_check to rule out corruption
  3. Retry the operation on a fresh connection; pre-commit disk state is unaffected
  4. Upgrade the engine - the cell-building code paths are under active development
Defensive patterns

Strategy: try-catch

Try / catch

let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
    conn.execute("DELETE FROM idx_t ON ...", ())  // any delete touching interior cells
}));
if result.is_err() { conn.close().ok(); /* reopen, verify, report */ }

Prevention

When it happens

Trigger: Interior-node replacement on DELETE where the payload Vec came out empty or truncated - a logic bug in the payload construction arms (TableLeafCell / IndexLeafCell rewriting) or an allocation failure swallowed earlier in the chain.

Common situations: Engine regressions in cell serialization, corrupted cell metadata producing zero-length writes, allocation-failure paths in with_btree_allocation_site! macros.

Related errors


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20). Data as JSON: /api/errors/55a365b05ede7f06. Report an issue: GitHub.