tursodatabase/turso · error

MVCC logical pull is not supported for in-memory sync server

Error message

MVCC logical pull is not supported for in-memory sync server databases

What it means

MVCC logical pulls stream bytes from the on-disk .db-log file derived from the server's db_path; an in-memory (":memory:") database has no such file, so db_file_path refuses early with this error. In the current server the error is intercepted in handle_logical_pull_updates, which logs and transparently downgrades the request to an incremental page pull, so clients normally never see it. It escapes only through new call sites of logical_log_path/db_file_path that lack the is_in_memory_db_path guard.

Source

Thrown at cli/sync_server.rs:906

            .iter()
            .find_map(|(boundary, crc)| (*boundary == offset).then_some(*crc))
            .ok_or_else(|| {
                anyhow!("MVCC logical pull offset is not a transaction boundary: {offset}")
            })
    }
}

fn logical_log_path(db_path: &str) -> Result<PathBuf> {
    Ok(db_file_path(db_path)?.with_extension("db-log"))
}

fn is_in_memory_db_path(db_path: &str) -> bool {
    db_path == ":memory:"
}

fn db_file_path(db_path: &str) -> Result<PathBuf> {
    if is_in_memory_db_path(db_path) {
        return Err(anyhow!(
            "MVCC logical pull is not supported for in-memory sync server databases"
        ));
    }
    let path = if let Some(rest) = db_path.strip_prefix("file:") {
        rest.split_once('?').map_or(rest, |(path, _)| path)
    } else {
        db_path
    };
    Ok(PathBuf::from(path))
}

fn parse_mvcc_revision_offset(revision: &str, legacy_default: u64) -> Result<u64> {
    if revision.is_empty() {
        return Ok(0);
    }
    if let Some((generation, offset)) = revision.split_once(":o") {
        let generation = generation
            .strip_prefix('g')

View on GitHub (pinned to bad083fafb)

Solutions

  1. Use a file-backed database path when MVCC logical pulls must actually be exercised end to end.
  2. Keep ":memory:" and rely on the built-in page-pull fallback.
  3. When adding code that opens the .db-log, mirror the existing guard: check is_in_memory_db_path(&self.db_path) before calling logical_log_path.

Example fix

// before
let log_path = logical_log_path(&self.db_path)?;

// after
if is_in_memory_db_path(&self.db_path) {
    return self.handle_page_pull_updates(req, PullUpdatesApplyMode::Incremental);
}
let log_path = logical_log_path(&self.db_path)?;
Defensive patterns

Strategy: validation

Validate before calling

fn supports_logical_pull(db_path: &str) -> bool {
    !db_path.is_empty() && db_path != ":memory:"
}
// before requesting stream_kind = MvccLogicalLog
assert!(supports_logical_pull(&server_db_path), "logical pulls need a file-backed db");

Prevention

When it happens

Trigger: Constructing TursoSyncServer with db_path=":memory:" (MVCC enabled) and code reaching logical_log_path directly instead of going through handle_logical_pull_updates' guarded path.

Common situations: Fast test loops that use an in-memory server database while MVCC sync features are enabled; new server code added without the in-memory guard.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/91a2b97877b0edb3. Report an issue: GitHub.