tursodatabase/turso · critical

invalid page size stored

Error message

invalid page size stored

What it means

Pager::get_page_size_unchecked() reads the atomic page_size, asserts it is non-zero (turso_assert_ne!), then validates it with PageSize::new(value).expect("invalid page size stored"). PageSize::new only accepts powers of two in [512, 65536]; a non-zero value outside that set (e.g. 3000 or 131072) panics.

Source

Thrown at core/storage/pager.rs:3103

        self.dirty_pages.write().clear();
        Ok(())
    }

    /// Get the current page size. Returns None if not set yet.
    pub fn get_page_size(&self) -> Option<PageSize> {
        let value = self.page_size.load(Ordering::SeqCst);
        if value == 0 {
            None
        } else {
            PageSize::new(value)
        }
    }

    /// Get the current page size, panicking if not set.
    pub fn get_page_size_unchecked(&self) -> PageSize {
        let value = self.page_size.load(Ordering::SeqCst);
        turso_assert_ne!(value, 0);
        PageSize::new(value).expect("invalid page size stored")
    }

    pub(crate) fn has_wal(&self) -> bool {
        self.wal.is_some()
    }

    #[cfg(test)]
    pub(crate) fn wal_shared_ptr(&self) -> Option<usize> {
        self.wal
            .as_ref()
            .and_then(|wal| wal.as_any().downcast_ref::<crate::storage::wal::WalFile>())
            .map(crate::storage::wal::WalFile::shared_ptr)
    }

    /// Set the page size. Used internally when page size is determined.
    pub fn set_page_size(&self, size: PageSize) {
        self.page_size.store(size.get(), Ordering::SeqCst);
    }

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Prefer the checked variant get_page_size() (returns Option) and handle None instead of get_page_size_unchecked()
  2. Validate the header at open (PRAGMA page_size, integrity check) when loading untrusted files
  3. If setting the size programmatically, construct PageSize::new(v) first and store the validated value

Example fix

// before
let page_size = pager.get_page_size_unchecked(); // panics on invalid stored value

// after
let Some(page_size) = pager.get_page_size() else {
    return Err(LimboError::Corrupt("page size not set or invalid".into()));
};
Defensive patterns

Strategy: validation

Validate before calling

// Prefer the checked accessor and handle the unset/invalid case:
match pager.get_page_size() {
    Some(ps) => { /* proceed with ps */ }
    None => return Err(LimboError::Corrupt("page size not set or invalid".into())),
}
// When opening untrusted files, validate up front:
let ps = conn.query_row("PRAGMA page_size", [], |r| r.get::<_, i64>(0))?;

Prevention

When it happens

Trigger: A bogus page size was stored into the pager - a corrupted or unvalidated database header value read at open time, or embedder code writing an arbitrary usize into pager.page_size instead of a PageSize-validated value.

Common situations: Opening corrupted or hand-crafted/fuzzed database files, page-size plumbing regressions between engine versions, programmatic page-size changes without validation.

Related errors


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