tursodatabase/turso · error

Page size too small, a ptrmap page cannot map any db pages.

Error message

Page size too small, a ptrmap page cannot map any db pages.

What it means

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.

Source

Thrown at core/storage/pager.rs:6374

    /// Determines if a given page number `db_page_no` (1-indexed) is a pointer map page in a database with autovacuum enabled
    pub fn is_ptrmap_page(db_page_no: u32, page_size: usize) -> bool {
        //  The first page cannot be a ptrmap page because its for the schema
        if db_page_no == 1 {
            return false;
        }
        if db_page_no == FIRST_PTRMAP_PAGE_NO {
            return true;
        }
        get_ptrmap_page_no_for_db_page(db_page_no, page_size) == db_page_no
    }

    /// Calculates which pointer map page (1-indexed) contains the entry for `db_page_no_to_query` (1-indexed).
    /// `db_page_no_to_query` is the page whose ptrmap entry we are interested in.
    pub fn get_ptrmap_page_no_for_db_page(db_page_no_to_query: u32, page_size: usize) -> u32 {
        let group_size = ptrmap_page_cycle_length(page_size) as u32;
        if group_size == 0 {
            panic!("Page size too small, a ptrmap page cannot map any db pages.");
        }

        let effective_page_index = db_page_no_to_query - FIRST_PTRMAP_PAGE_NO;
        let group_idx = effective_page_index / group_size;

        (group_idx * group_size) + FIRST_PTRMAP_PAGE_NO
    }

    /// Calculates the byte offset of the entry for `db_page_no_to_query` (1-indexed)
    /// within its pointer map page (`ptrmap_page_no`, 1-indexed).
    pub fn get_ptrmap_offset_in_page(
        db_page_no_to_query: u32,
        ptrmap_page_no: u32,
        page_size: usize,
    ) -> Result<usize> {
        // The data pages mapped by `ptrmap_page_no` are:
        // `ptrmap_page_no + 1`, `ptrmap_page_no + 2`, ..., up to `ptrmap_page_no + n_data_pages_per_group`.
        // `db_page_no_to_query` must be one of these.

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Validate page_size is >= 512 and a power of two before ptrmap computations
  2. If caused by a corrupt file: restore from backup or rebuild the database
  3. Fix the test to use a legal page size

Example fix

// before
let p = get_ptrmap_page_no_for_db_page(page, tiny_page_size); // panics: zero entries fit

// after
assert!(page_size >= 512 && page_size.is_power_of_two());
let p = get_ptrmap_page_no_for_db_page(page, page_size);
Defensive patterns

Strategy: validation

Validate before calling

fn valid_page_size(ps: usize) -> bool {
    (512..=65536).contains(&ps) && ps.is_power_of_two()
}
assert!(valid_page_size(page_size));

Prevention

When it happens

Trigger: 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).

Common situations: Unit tests with hand-rolled page sizes; fuzzed or corrupt database headers skipping validation.

Related errors


AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20). Data as JSON: /api/errors/8f8a4b5989e396ea. Report an issue: GitHub.