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
- Prefer the checked variant get_page_size() (returns Option) and handle None instead of get_page_size_unchecked()
- Validate the header at open (PRAGMA page_size, integrity check) when loading untrusted files
- 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
- Avoid get_page_size_unchecked() in embedder code; use the Option-returning get_page_size()
- Validate PRAGMA page_size / run integrity checks before operating on untrusted database files
- Only store PageSize-validated values when configuring sizes programmatically
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
- Page size too small, a ptrmap page cannot map any db pages.
- buffer not loaded
- DB should not be initialized and should not do any IO
- subjournal must be opened
- in practice, clear_savepoints() should never fail as it uses
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/8b9c89ffcc23a622.
Report an issue: GitHub.