diem/diem · critical
Transaction versions are not consecutive.
Error message
Transaction versions are not consecutive.
What it means
The transaction store's ledger-info iterator (next_impl) walks consecutive transaction versions from start_version to end_version. DiemDB guarantees every version in a committed range exists, so if the underlying CF iterator yields a version other than expected_next_version, the DB is missing or has extra versions and is considered corrupt.
Source
Thrown at storage/diemdb/src/transaction_store/mod.rs:160
Ok(())
}
}
pub struct TransactionIter<'a> {
inner: SchemaIterator<'a, TransactionSchema>,
expected_next_version: Version,
end_version: Version,
}
impl<'a> TransactionIter<'a> {
fn next_impl(&mut self) -> Result<Option<Transaction>> {
if self.expected_next_version >= self.end_version {
return Ok(None);
}
let ret = match self.inner.next().transpose()? {
Some((version, transaction)) => {
ensure!(
version == self.expected_next_version,
"Transaction versions are not consecutive.",
);
self.expected_next_version += 1;
Some(transaction)
}
None => None,
};
Ok(ret)
}
}
impl<'a> Iterator for TransactionIter<'a> {
type Item = Result<Transaction>;
fn next(&mut self) -> Option<Self::Item> {
self.next_impl().transpose()View on GitHub (pinned to fc4714a8ea)
Solutions
- Treat the DB as corrupt: re-sync the node from a trusted snapshot or genesis.
- Verify the transaction CF with diem-db-tooling / inspector to find the gap.
- Ensure no external pruning job removed versions inside ranges still being iterated.
Defensive patterns
Strategy: fallback
Validate before calling
// Before iterating, confirm the DB is healthy:
let startup = db.get_startup_info().expect("db open");
let latest = startup.unwrap().latest_ledger_info.ledger_info().version();
assert!(start <= end && end <= latest, "requested range beyond stored versions"); Try / catch
match iter_result {
Err(e) if e.to_string().contains("not consecutive") => {
error!("transaction store corrupt at {}..{}", start, end);
// halt, alert, re-sync from snapshot
}
other => other?,
} Prevention
- Do not run external pruning inside version ranges still served to clients.
- Always restore full, verified snapshots; never splice partial DB directories.
- Monitor RocksDB for corruption events and alerts.
- Keep periodic backups so re-sync cost is bounded.
When it happens
Trigger: Iterating transactions via get_transactions / the TransactionStore iterator over a range where a version entry is missing or duplicated in the transaction CF, so the next item's version != expected_next_version.
Common situations: Corrupted or manually pruned RocksDB data, restoring partial backups that skip version ranges, or hardware/disk issues dropping SST entries.
Related errors
- Unexpected data len {}, expected {}.
- Unexpected data len {}, expected to be greater than {}.
- DB corruption: account transactions sequence numbers are not
- DB corruption: account transaction versions are not strictly
- ConsensusDB open failed; unable to continue
AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04).
Data as JSON: /api/errors/0d7b902179d233d8.
Report an issue: GitHub.