{"record":{"id":"409a282e90d395e0","repo":"tursodatabase/turso","slug":"buffer-not-loaded","errorCode":null,"errorMessage":"buffer not loaded","messagePattern":"buffer not loaded","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"core/storage/pager.rs","lineNumber":164,"sourceCode":"\n    /// Creates a new PageInner with an owned buffer.\n    pub fn from_buffer(buffer: Buffer) -> Self {\n        Self {\n            flags: AtomicUsize::new(0),\n            id: 0,\n            pin_count: AtomicUsize::new(0),\n            wal_tag: AtomicU64::new(TAG_UNSET),\n            buffer: Some(Arc::new(buffer)),\n            overflow_cells: crate::alloc::vec![],\n        }\n    }\n    /// Get the page buffer as a mutable slice. Panics if buffer not loaded.\n    #[inline]\n    #[allow(clippy::mut_from_ref)]\n    pub fn as_ptr(&self) -> &mut [u8] {\n        self.buffer\n            .as_ref()\n            .expect(\"buffer not loaded\")\n            .as_mut_slice()\n    }\n\n    /// The position where page content starts. It's 100 for page 1 (database file header is 100 bytes),\n    /// 0 for all other pages.\n    #[inline]\n    pub fn offset(&self) -> usize {\n        if self.id == 1 {\n            DatabaseHeader::SIZE\n        } else {\n            0\n        }\n    }\n\n    /// Read a u8 from the page content at the given offset, taking account the possible db header on page 1.\n    #[inline]\n    fn read_u8(&self, pos: usize) -> u8 {\n        let buf = self.as_ptr();","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/core/storage/pager.rs#L146-L182","documentation":"Page::as_ptr() (core/storage/pager.rs) hands out a mutable slice of the page buffer and expects buffer to be Some (\"buffer not loaded\"). Pages whose buffer was taken during eviction or never loaded have buffer=None; touching their contents through get_contents()/as_ptr() panics.","triggerScenarios":"Calling get_contents()/as_ptr() on a PageRef that was not (re)loaded - e.g. a page re-fetched from the cache after eviction without return_if_locked_maybe_load!, or a dirty page whose backing WAL frame was truncated by savepoint rollback.","commonSituations":"Custom btree/pager code skipping the load macros, heavy cache pressure evicting pages mid-operation, engine regressions in pin/reload discipline. The commit path already carries an explicit unloaded-page guard for this shape.","solutions":["Always acquire pages through pager.read_page() / return_if_locked_maybe_load! so the buffer is loaded before contents are touched","Check page.is_loaded() before accessing contents in any custom code","Treat occurrences inside engine paths as bugs - report them with a reproduction","Reduce cache pressure (larger page cache) to avoid eviction windows"],"exampleFix":"// before\nlet contents = page.get_contents(); // panics if evicted: buffer is None\nlet ptr = contents.as_ptr();\n\n// after\nif !page.is_loaded() {\n    return Err(LimboError::InternalError(format!(\"page {} buffer not loaded\", page.get().id)));\n}\nlet contents = page.get_contents();","handlingStrategy":"validation","validationCode":"// Before touching page contents in custom code over the pager/btree APIs:\nif !page.is_loaded() {\n    return Err(LimboError::InternalError(format!(\n        \"page {} buffer not loaded; re-read via pager.read_page()\", page.get().id\n    )));\n}","typeGuard":"fn is_page_loaded(page: &PageRef) -> bool {\n    page.is_loaded()\n}","tryCatchPattern":null,"preventionTips":["Acquire pages only through pager.read_page()/return_if_locked_maybe_load! which guarantee a loaded buffer","Never cache PageRefs across operations that can evict (cache pressure, savepoint rollback)","Check is_loaded() in debug assertions in custom storage code","Report engine-path occurrences upstream - the commit path already guards this shape explicitly"],"tags":["pager","page-buffer","eviction","panic"],"backgroundTag":"page-buffer-not-loaded","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}