tursodatabase/turso · critical

No WAL to checkpoint

Error message

No WAL to checkpoint

What it means

checkpoint_wal in the MVCC checkpoint state machine performs a TRUNCATE checkpoint but panics if self.pager.wal is None, i.e. the pager was opened without a WAL. The state machine should only run when a WAL exists, so hitting this panic means the checkpoint driver was started on a non-WAL (or already torn down) pager.

Source

Thrown at core/mvcc/database/checkpoint_state_machine.rs:1485

        let boundary = if self.mode.should_restart_log() {
            u64::MAX
        } else {
            self.durable_txid_max_new
        };
        let (c, outcome) = self.mvstore.storage.truncate(boundary)?;
        if self.mode.should_restart_log() {
            turso_assert!(
                matches!(outcome, LogicalLogTruncateOutcome::Truncated),
                "TRUNCATE checkpoint must clear the logical log"
            );
        }
        Ok(c)
    }

    /// Perform a TRUNCATE checkpoint on the WAL
    fn checkpoint_wal(&self) -> IOResultOr<CheckpointResult> {
        let Some(wal) = &self.pager.wal else {
            panic!("No WAL to checkpoint");
        };
        match wal.checkpoint(&self.pager, self.mode, self.sync_mode)? {
            IOResult::Done(result) => Ok(IOResult::Done(result)),
            IOResult::IO(io) => Ok(IOResult::IO(io)),
        }
    }

    /// Publish `nbackfills` after Passive backfill + DB sync. Skip Truncate/Restart.
    /// Leaves the checkpoint guard held until Finalize (same as the pager).
    fn publish_wal_backfill_if_needed(&mut self) {
        if self.mode.should_restart_log() {
            return;
        }
        let Some(result) = self.checkpoint_result.as_ref() else {
            return;
        };
        if result.wal_checkpoint_backfilled == 0 {
            return;

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Ensure the database is opened in WAL journal mode before triggering MVCC checkpointing.
  2. Avoid closing/destroying the database while a checkpoint is still pending; complete or cancel checkpointing first.
  3. File a bug with reproduction steps if this occurs in normal WAL-mode operation.
  4. If developing the engine, add a guard so the checkpoint state machine is never entered without a WAL.
Defensive patterns

Strategy: validation

Validate before calling

// Only schedule MVCC checkpointing when the pager actually has a WAL
if (db.pager.wal.is_some()) {
    checkpoint_driver.start();
}

Try / catch

// Rust panic: prevent entry into the state machine rather than catching it
assert!(pager.wal.is_some(), "checkpoint requires WAL mode");

Prevention

When it happens

Trigger: Driving the MVCC checkpoint state machine on a pager opened without WAL support, or after the WAL has been detached/closed while checkpointing is still in progress.

Common situations: Running MVCC-mode experiments with a journal mode that isn't WAL; shutting down a database while a background checkpoint is scheduled; engine development/fuzzing of the checkpoint path.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-09-06). Data as JSON: /api/errors/51fc8558a66efa3c. Report an issue: GitHub.