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

  1. Create the pool with BufferPool::begin_init(&io, arena_size) so the IO handle is stored before any finalize call
  2. Call finalize_with_page_size(page_size) only after the Database open sequence has run begin_init
  3. 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

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


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/5c31028f6b4eace9. Report an issue: GitHub.