tursodatabase/turso · error

invalid MVCC pull revision offset: {revision}: {err}

Error message

invalid MVCC pull revision offset: {revision}: {err}

What it means

The offset segment after ":o" in the client revision fails u64 parsing — e.g. "g1:olast", "g1:o-5", or a missing value like "g1:o". The generation parsed fine, so the message pinpoints only the offset part, with the ParseInt error appended.

Source

Thrown at cli/sync_server.rs:935

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')
            .ok_or_else(|| anyhow!("invalid MVCC pull revision generation: {revision}"))?
            .parse::<u64>()
            .map_err(|err| anyhow!("invalid MVCC pull revision generation: {revision}: {err}"))?;
        if generation != 1 {
            return Err(anyhow!(
                "sync_server supports only single-generation MVCC logical pulls: {revision}"
            ));
        }
        return offset
            .parse::<u64>()
            .map_err(|err| anyhow!("invalid MVCC pull revision offset: {revision}: {err}"));
    }
    // Older page bootstrap responses from this test server used WAL frame
    // numbers. Treat them as "the page snapshot already includes the current
    // logical log" so the required follow-up logical pull becomes a no-op.
    Ok(legacy_default)
}

fn scan_mvcc_log(log: &[u8]) -> Result<MvccLogSnapshot> {
    if log.is_empty() {
        return Ok(MvccLogSnapshot {
            end_offset: 0,
            crc_by_offset: vec![(0, 0)],
        });
    }
    if log.len() < MVCC_LOG_HEADER_SIZE {
        return Err(anyhow!(
            "truncated MVCC logical log header: len={} header_size={}",
            log.len(),

View on GitHub (pinned to bad083fafb)

Solutions

  1. Validate the revision against the g<digits>:o<digits> grammar before sending.
  2. Use server-provided revision strings verbatim; never template them.
  3. Send an empty client_revision when the correct offset is unknown.

Example fix

// before
req.client_revision = "g1:oend".to_string();

// after
req.client_revision = "g1:o128".to_string();
Defensive patterns

Strategy: validation

Validate before calling

fn valid_offset(rev: &str) -> bool {
    rev.strip_prefix("g1:o").map(|o| !o.is_empty() && o.chars().all(|c| c.is_ascii_digit())).unwrap_or(false)
}

Try / catch

On 500 'invalid MVCC pull revision offset', substitute the last server-provided revision (or empty string for offset 0) and retry once.

Prevention

When it happens

Trigger: Hand-crafted or template-substituted revision strings whose offset is non-numeric, signed, or empty.

Common situations: Tests substituting symbolic names into the revision format; persisted state corrupted or truncated at the offset field.

Related errors


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