tursodatabase/turso · error
invalid MVCC pull revision generation: {revision}: {err}
Error message
invalid MVCC pull revision generation: {revision}: {err} What it means
Same revision grammar as the sibling error: the generation segment starts with 'g' but the remaining digits do not parse as u64 — e.g. "g:o9", "g1x:o5", "g-1:o3". The underlying ParseInt error text is appended to the message so the malformed segment is identifiable.
Source
Thrown at cli/sync_server.rs:927
}
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')
.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 {View on GitHub (pinned to bad083fafb)
Solutions
- Validate the revision against the g<digits>:o<digits> grammar before sending.
- Echo back server-provided revision strings verbatim instead of reconstructing them.
- Send an empty client_revision when in doubt; the server then defines the starting offset.
Example fix
// before req.client_revision = "gx1:o128".to_string(); // after req.client_revision = "g1:o128".to_string();
Defensive patterns
Strategy: validation
Validate before calling
fn is_server_revision(rev: &str) -> bool {
if rev.is_empty() || rev.chars().all(|c| c.is_ascii_digit()) {
return true;
}
matches!(
rev.strip_prefix('g').and_then(|r| r.split_once(":o")),
Some((g, o)) if g.parse::<u64>().is_ok() && o.parse::<u64>().is_ok()
)
} Try / catch
On 500 'invalid MVCC pull revision generation' with a parse error, replace the malformed revision with the last server-provided one (or empty string) and retry once.
Prevention
- Never hand-edit generation digits in persisted revisions.
- Validate revisions against the grammar before sending.
When it happens
Trigger: Hand-edited revision strings where the generation contains non-numeric characters, a sign, or is empty after the 'g'.
Common situations: Manual state surgery on persisted sync state; tests and scripts that template the revision string from unvalidated input.
Related errors
- invalid MVCC pull revision generation: {revision}
- invalid MVCC pull revision offset: {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/b281a56db827ced2.
Report an issue: GitHub.