tursodatabase/turso · critical

PreparingWalStart requires a WAL

Error message

PreparingWalStart requires a WAL

What it means

Cache-spill state machine: after the WAL header write (SpillState::PreparingWalStart) is durable, the pager issues the fsync that marks the WAL initialized via self.wal.as_ref().expect("PreparingWalStart requires a WAL"). Reaching this state on a pager with no WAL attached (self.wal == None) panics.

Source

Thrown at core/storage/pager.rs:4188

                                let completions = self.spill_pages_to_disk(&pages, &mut group)?;
                                if completions.is_empty() {
                                    self.finish_ephemeral_spill(&pages);
                                    return Ok(IOResult::Done(()));
                                }
                                *self.spill_state.write() =
                                    SpillState::WritingToDisk { pages, completions };
                                io_yield_one!(group.build());
                            }
                        }
                    }
                }
                SpillState::PreparingWalStart { pages, completion } => {
                    if !completion.succeeded() {
                        io_yield_one!(completion);
                    }
                    // Header (and any truncate) durable — issue the fsync that
                    // marks the WAL initialized.
                    let wal = self.wal.as_ref().expect("PreparingWalStart requires a WAL");
                    let finish_c = wal.prepare_wal_finish(self.get_sync_type())?;
                    *self.spill_state.write() = SpillState::PreparingWalFinish {
                        pages,
                        completion: finish_c,
                    };
                    continue;
                }
                SpillState::PreparingWalFinish { pages, completion } => {
                    if !completion.succeeded() {
                        io_yield_one!(completion);
                    }
                    // WAL is now initialized; append the spill frames.
                    return self.spill_append_frames_to_wal(pages);
                }
                SpillState::WritingToWal { pages, completions } => {
                    for c in &completions {
                        if !c.succeeded() {
                            io_yield_one!(c.clone());

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Report to Turso: spill-without-WAL should be rejected with an error, not a panic
  2. Open file-backed databases in WAL mode when large write statements are expected
  3. Increase the page cache so the dirty set fits without spilling
  4. In embedder code, disable spilling explicitly on WAL-less databases with pager.set_spill_enabled(false)

Example fix

// before: in-memory database, spill enabled by default under cache pressure
let db = Database::open_file(io, ":memory:", false)?; // no WAL
// huge INSERT ... overwhelms cache -> spill -> panic

// after: keep dirty set within cache / disable spill on WAL-less pagers
pager.set_spill_enabled(false);
// and/or commit in smaller batches
Defensive patterns

Strategy: validation

Validate before calling

// For WAL-less databases (in-memory or otherwise), keep the dirty set below
// the cache so spill never triggers, or disable spill explicitly in embedder code:
if !pager.has_wal_enabled_for_your_setup() {
    pager.set_spill_enabled(false);
}
// Application level: open file databases in WAL mode before large writes:
conn.execute("PRAGMA journal_mode=WAL", ())?;

Try / catch

let result = std::panic::catch_unwind(AssertUnwindSafe(|| do_big_write(&conn)));
if result.is_err() { conn.close().ok(); /* reopen in WAL mode or raise cache size */ }

Prevention

When it happens

Trigger: Cache spill triggered (dirty pages exceed the page cache) on a database opened without a WAL - in-memory databases or a journal configuration where Pager::wal was never set - so the spill state machine advances into WAL-dependent states.

Common situations: Large single statements on :memory: databases overflowing the cache, engine regressions allowing spill without WAL, custom open paths producing a WAL-less pager.

Related errors


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