tikv/tikv · critical
txn record found but not expected: {:?} {} {:?} {:?} [region
Error message
txn record found but not expected: {:?} {} {:?} {:?} [region_id={}] What it means
During a rollback (`rollback_lock`), the code expects that when a transaction commit record exists it is either absent (allowing overlapped writes) or a Rollback. If a WRITE record of any other type (Put/Delete/Lock) is found for the transaction being rolled back, the transaction is actually committed — rolling it back would be incorrect — so TiKV panics with the record, commit_ts, txn, lock, and region id for diagnosis.
Source
Thrown at src/storage/txn/actions/check_txn_status.rs:314
}
}
pub fn rollback_lock(
txn: &mut MvccTxn,
reader: &mut SnapshotReader<impl Snapshot>,
key: Key,
lock: &Lock,
is_pessimistic_txn: bool,
collapse_rollback: bool,
) -> Result<Option<ReleasedLock>> {
// Lock is never shared in the current branch's architecture - shared locks use
// SharedLocks type
let overlapped_write = match reader.get_txn_commit_record(&key)? {
TxnCommitRecord::None { overlapped_write } => overlapped_write,
TxnCommitRecord::SingleRecord { write, commit_ts }
if write.write_type != WriteType::Rollback =>
{
panic!(
"txn record found but not expected: {:?} {} {:?} {:?} [region_id={}]",
write,
commit_ts,
txn,
lock,
reader.reader.snapshot_ext().get_region_id().unwrap_or(0)
)
}
_ => return Ok(txn.unlock_key(key, is_pessimistic_txn, TimeStamp::zero())),
};
// If prewrite type is DEL or LOCK or PESSIMISTIC, it is no need to delete
// value.
if lock.short_value.is_none() && lock.lock_type == LockType::Put {
txn.delete_value(key.clone(), lock.ts);
}
// (1) The primary key of any transaction needs to be protected.View on GitHub (pinned to 78aedc1c81)
Solutions
- Treat this as a serious invariant violation: collect the panic log (write, commit_ts, txn, lock, region_id) and file it with TiKV support.
- Verify the transaction's commit status via TiDB/tikv-ctl (`check_txn_status`) before issuing cleanup/rollback for possibly-committed locks.
- Check for known bugs in your TiKV version around `get_txn_commit_record` overlap handling and upgrade to a patched release.
- Use the region/transaction recovery tooling (unsafe recovery, online unsafe destroy) only with support guidance; do not manually rewrite WRITE CF records.
Defensive patterns
Strategy: validation
Validate before calling
// before requesting cleanup/rollback, confirm the txn is not committed
let status = check_txn_status(txn_key, check_ts).await?;
if status.lock_info.is_none() && status.commit_ts.is_some() {
skip_rollback("txn already committed");
} Type guard
fn safe_to_rollback(rec: &TxnCommitRecord) -> bool {
match rec {
TxnCommitRecord::None { .. } => true,
TxnCommitRecord::SingleRecord { write, .. } => write.write_type == WriteType::Rollback,
_ => false,
}
} Try / catch
match result {
Err(e) if e.message.contains("txn record found but not expected") => {
capture_panic_context(region_id, txn);
escalate_to_support(e); // do not retry rollback
}
other => propagate(other),
} Prevention
- Keep TiDB/TiKV versions aligned to avoid stale lock-resolution races.
- Monitor lock-resolve latency; long stale locks increase commit/rollback races.
- After region leader changes, let resolution requests use fresh snapshots.
- Upgrade to releases with fixes for check_txn_status overlap handling.
- Never manually craft cleanup requests for transactions that may have committed.
When it happens
Trigger: `rollback_lock` calls `get_txn_commit_record` and matches `TxnCommitRecord::SingleRecord` whose `write_type != WriteType::Rollback` — i.e. attempting to roll back a lock whose transaction already has a committed Put/Delete/Lock write. Raised from callers like `cleanup`, `check_txn_status_lock_exists`, and `check_txn_status_from_pessimistic_primary_lock`.
Common situations: Client/TiDB issuing rollback (cleanup) for a transaction that concurrently committed (race between commit and stale-lock cleanup); stale lock-resolution requests delayed past commit; region leader change with stale reads; primary-lock cleanup after the transaction already committed.
Related errors
- ime cross check fail(key should exist): default not found;
- ime cross check fail(key should exist): write cf not match;
- ime cross check fail(key should exist): miss valid mvcc vers
- ime cross check fail(key should exist): miss valid mvcc vers
- ime cross check fail(key should exist): miss valid mvcc vers
AI-assisted analysis of tikv/tikv@78aedc1c81 (2026-09-03).
Data as JSON: /api/errors/6c8f142ae0fa40c0.
Report an issue: GitHub.