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

  1. Treat the DB as corrupt: re-sync the node from a trusted snapshot or genesis.
  2. Verify the transaction CF with diem-db-tooling / inspector to find the gap.
  3. 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

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


AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04). Data as JSON: /api/errors/0d7b902179d233d8. Report an issue: GitHub.