{"record":{"id":"8f8a4b5989e396ea","repo":"tursodatabase/turso","slug":"page-size-too-small-a-ptrmap-page-cannot-map-any","errorCode":null,"errorMessage":"Page size too small, a ptrmap page cannot map any db pages.","messagePattern":"Page size too small, a ptrmap page cannot map any db pages\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/storage/pager.rs","lineNumber":6374,"sourceCode":"\n    /// Determines if a given page number `db_page_no` (1-indexed) is a pointer map page in a database with autovacuum enabled\n    pub fn is_ptrmap_page(db_page_no: u32, page_size: usize) -> bool {\n        //  The first page cannot be a ptrmap page because its for the schema\n        if db_page_no == 1 {\n            return false;\n        }\n        if db_page_no == FIRST_PTRMAP_PAGE_NO {\n            return true;\n        }\n        get_ptrmap_page_no_for_db_page(db_page_no, page_size) == db_page_no\n    }\n\n    /// Calculates which pointer map page (1-indexed) contains the entry for `db_page_no_to_query` (1-indexed).\n    /// `db_page_no_to_query` is the page whose ptrmap entry we are interested in.\n    pub fn get_ptrmap_page_no_for_db_page(db_page_no_to_query: u32, page_size: usize) -> u32 {\n        let group_size = ptrmap_page_cycle_length(page_size) as u32;\n        if group_size == 0 {\n            panic!(\"Page size too small, a ptrmap page cannot map any db pages.\");\n        }\n\n        let effective_page_index = db_page_no_to_query - FIRST_PTRMAP_PAGE_NO;\n        let group_idx = effective_page_index / group_size;\n\n        (group_idx * group_size) + FIRST_PTRMAP_PAGE_NO\n    }\n\n    /// Calculates the byte offset of the entry for `db_page_no_to_query` (1-indexed)\n    /// within its pointer map page (`ptrmap_page_no`, 1-indexed).\n    pub fn get_ptrmap_offset_in_page(\n        db_page_no_to_query: u32,\n        ptrmap_page_no: u32,\n        page_size: usize,\n    ) -> Result<usize> {\n        // The data pages mapped by `ptrmap_page_no` are:\n        // `ptrmap_page_no + 1`, `ptrmap_page_no + 2`, ..., up to `ptrmap_page_no + n_data_pages_per_group`.\n        // `db_page_no_to_query` must be one of these.","sourceCodeStart":6356,"sourceCodeEnd":6392,"githubUrl":"https://github.com/tursodatabase/turso/blob/492c4a71cd7c2649e7df83da1471b74f4b1c7aa9/core/storage/pager.rs#L6356-L6392","documentation":"A pointer-map page holds one 5-byte entry per mapped database page; ptrmap_page_cycle_length derives how many entries fit in a page. If the page size is so small that zero entries fit, get_ptrmap_page_no_for_db_page panics. With SQLite's minimum page size of 512 bytes this is unreachable from valid databases - it guards against malformed or custom page sizes reaching the ptrmap math.","triggerScenarios":"Computing ptrmap page numbers with a page size smaller than the entry size: unit tests passing tiny page sizes, or corrupted-header parsing feeding an invalid page size onward (auto_vacuum pointer-map code).","commonSituations":"Unit tests with hand-rolled page sizes; fuzzed or corrupt database headers skipping validation.","solutions":["Validate page_size is >= 512 and a power of two before ptrmap computations","If caused by a corrupt file: restore from backup or rebuild the database","Fix the test to use a legal page size"],"exampleFix":"// before\nlet p = get_ptrmap_page_no_for_db_page(page, tiny_page_size); // panics: zero entries fit\n\n// after\nassert!(page_size >= 512 && page_size.is_power_of_two());\nlet p = get_ptrmap_page_no_for_db_page(page, page_size);","handlingStrategy":"validation","validationCode":"fn valid_page_size(ps: usize) -> bool {\n    (512..=65536).contains(&ps) && ps.is_power_of_two()\n}\nassert!(valid_page_size(page_size));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize page-size validation at header parse time so ptrmap math never sees garbage","Point fuzz targets at the validator so corrupt sizes are rejected at the boundary"],"tags":["storage","pager","ptrmap","page-size","validation","panic"],"backgroundTag":"invalid-page-size","analyzedSha":"492c4a71cd7c2649e7df83da1471b74f4b1c7aa9","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}