tursodatabase/turso · critical
Pool not initialized
Error message
Pool not initialized
What it means
PoolInner::init_arenas() (core/storage/buffer_pool.rs) requires self.io to have been stored by BufferPool::begin_init(io, arena_size). The expect("Pool not initialized") fires when finalize_with_page_size(page_size) triggers arena creation on a pool that was never handed an Arc<dyn IO> - the arena needs the IO handle to register its buffers.
Source
Thrown at core/storage/buffer_pool.rs:285
.as_ref()
.and_then(|arena| Arena::try_alloc(arena, db_page_size))
.unwrap_or_else(|| Buffer::new_temporary(db_page_size))
}
fn get_wal_frame_buffer(&mut self) -> Buffer {
let len = self.get_db_page_size() + WAL_FRAME_HEADER_SIZE;
self.wal_frame_arena
.as_ref()
.and_then(|wal_arena| Arena::try_alloc(wal_arena, len))
.unwrap_or_else(|| Buffer::new_temporary(len))
}
/// Allocate a new arena for the pool to use
fn init_arenas(&mut self) -> crate::Result<()> {
let db_page_size = self.get_db_page_size();
let arena_size = self.arena_size;
let io = self.io.as_ref().expect("Pool not initialized").clone();
// Create regular page arena
match Arena::new(db_page_size, arena_size, &io) {
Ok(arena) => {
tracing::trace!(
"added arena {} with size {} MB and slot size {}",
arena.id,
arena_size / (1024 * 1024),
db_page_size
);
self.page_arena = Some(Arc::new(arena));
}
Err(e) => {
tracing::error!("Failed to create arena: {:?}", e);
return Err(LimboError::InternalError(format!(
"Failed to create arena: {e}",
)));
}View on GitHub (pinned to 244cde92a7)
Solutions
- Create the pool with BufferPool::begin_init(&io, arena_size) so the IO handle is stored before any finalize call
- Call finalize_with_page_size(page_size) only after the Database open sequence has run begin_init
- If constructing pools manually in tests, pass the same Arc<dyn IO> you use for the database file
Example fix
// before let pool = make_pool_without_io(); // constructed without begin_init pool.finalize_with_page_size(4096)?; // panics: init_arenas() has no io // after let pool = BufferPool::begin_init(&io, arena_size); // stores Arc<dyn IO> pool.finalize_with_page_size(4096)?; // init_arenas() succeeds
Defensive patterns
Strategy: validation
Validate before calling
// When wiring the pool manually, always create it through begin_init so the // IO handle is stored before finalize_with_page_size can run: let pool = BufferPool::begin_init(&io, arena_size); // io: Arc<dyn IO> pool.finalize_with_page_size(page_size)?; // now init_arenas() finds self.io
Prevention
- Never construct BufferPool instances outside the documented begin_init/finalize_with_page_size flow
- Pass the same Arc<dyn IO> used for the database file into begin_init
- Add a debug_assert in embedder code that the pool came from begin_init before calling finalize
When it happens
Trigger: Calling finalize_with_page_size() (directly or via the Database open flow) on a BufferPool constructed through a path that skips begin_init - custom embedder code or unit tests building the pool manually without an IO implementation.
Common situations: Embedding turso core directly in tests, wiring a custom IO driver after pool creation, API changes between versions where pool construction was refactored.
Related errors
- mmap failed: {}
- munmap failed: {}
- {name} virtual table creation should not fail
- buffer not loaded
- OpenRead on pseudo cursor
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/5c31028f6b4eace9.
Report an issue: GitHub.