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
- Validate the revision against the g<digits>:o<digits> grammar before sending.
- Use server-provided revision strings verbatim; never template them.
- 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
- Never template the offset from unvalidated input.
- Echo server-provided revisions verbatim.
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
- invalid MVCC pull revision generation: {revision}
- invalid MVCC pull revision generation: {revision}: {err}
- MVCC logical pull revision is from the future: client_offset
- MVCC logical pull offset is not a transaction boundary: {off
- sync_server supports only single-generation MVCC logical pul
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/caa6eaf22a9280bf.
Report an issue: GitHub.