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

  1. Treat this as a serious invariant violation: collect the panic log (write, commit_ts, txn, lock, region_id) and file it with TiKV support.
  2. Verify the transaction's commit status via TiDB/tikv-ctl (`check_txn_status`) before issuing cleanup/rollback for possibly-committed locks.
  3. Check for known bugs in your TiKV version around `get_txn_commit_record` overlap handling and upgrade to a patched release.
  4. 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

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


AI-assisted analysis of tikv/tikv@78aedc1c81 (2026-09-03). Data as JSON: /api/errors/6c8f142ae0fa40c0. Report an issue: GitHub.