{"record":{"id":"8f53ce4b15a3e545","repo":"tikv/tikv","slug":"cannot-resolve-the-conflict-for-key","errorCode":null,"errorMessage":"cannot resolve the conflict {} for key {}","messagePattern":"cannot resolve the conflict (.+?) for key (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"components/compact-log-backup/src/compaction/exec.rs","lineNumber":194,"sourceCode":"                (Rollback | Put, Put) if wb.has_overlapped_rollback => Some(Ordering::Less),\n\n                // Rollback -> Protected Rollback.\n                // Keep the protected one.\n                // This was observed in some versions and shouldn't happen normally.\n                (Rollback, Rollback) if wa.is_protected() => Some(Ordering::Greater),\n                (Rollback, Rollback) if wb.is_protected() => Some(Ordering::Less),\n\n                // No comparing rule here.\n                _ => None,\n            }\n        };\n\n        sanity_check(&wa, &wb);\n        let maybe_ord = partial_cmp(&wa, &wb);\n        info!(\"resolve conflict result.\"; \"conflict_id\" => cid, \"order\" => ?maybe_ord);\n        match maybe_ord {\n            Some(Ordering::Greater) => std::mem::swap(a, b),\n            None => panic!(\n                \"cannot resolve the conflict {} for key {}\",\n                cid,\n                redact(&a.key)\n            ),\n\n            Some(_) => {}\n        }\n    }\n\n    fn update_checksum_diff(\n        c: &Subcompaction,\n        a: &mut Record,\n        b: &mut Record,\n        diff: &mut ChecksumDiff,\n    ) {\n        Self::resolve(c, a, b);\n\n        diff.removed_key += 1;","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/tikv/tikv/blob/78aedc1c81ef3f7d8bacc6e9d09f56460f134937/components/compact-log-backup/src/compaction/exec.rs#L176-L212","documentation":"This panic comes from the log-backup subcompaction conflict resolver in compact-log-backup. When two different records share the same user key in the write CF, `resolve` tries to order them via a partial ordering over WriteRef (overlapped-rollback Puts/Rollbacks, protected Rollbacks). If the write types fall into a combination with no comparison rule, `partial_cmp` returns `None` and TiKV panics rather than silently picking a winner, because choosing the wrong record could corrupt transactional data.","triggerScenarios":"Running PITR log-backup subcompactions where two input SSTs contain conflicting write-CF records for the same key whose write types don't match any known rule (e.g. a Delete vs a plain Rollback, or two non-protected Rollbacks with different content), typically caused by records written by older TiKV versions or by a bug upstream.","commonSituations":"Log backup compaction after restoring from backup taken with an older TiKV; data written during versions that produced non-protected rollbacks or collapsed-rollback patterns the resolver doesn't recognize; corrupted or externally-modified backup SST files.","solutions":["Capture the log with the key (redacted) and conflict_id and report to TiKV — this indicates data shapes the resolver doesn't know","Pin/upgrade to a TiKV version whose `partial_cmp` in components/compact-log-backup/src/compaction/exec.rs covers the offending write-type pair","Exclude the affected log-backup segment from compaction until the resolver is patched (limit compaction range to avoid the conflicting key range)","Verify backup data integrity: check the SSTs in the involved subcompaction for corruption or manual modification"],"exampleFix":"// before (resolver has no rule for the pair)\n(Rollback, Rollback) if wa.is_protected() => Some(Ordering::Greater),\n// after (add the missing rule, e.g. keep newer/protected rollback)\n(Rollback, Rollback) if wb.is_protected() => Some(Ordering::Less),\n(Rollback, Delete) => Some(Ordering::Less),","handlingStrategy":"validation","validationCode":"// Before running subcompactions over a range, inspect write-CF record pairs\nfn resolvable(wa: &WriteRef, wb: &WriteRef) -> bool {\n    use WriteType::*;\n    matches!(\n        (wa.write_type, wb.write_type),\n        (Put, Rollback | Put) | (Rollback, Put) | (Rollback, Rollback)\n    )\n}","typeGuard":"fn has_comparison_rule(w: &WriteRef) -> bool {\n    use WriteType::*;\n    matches!(w.write_type, Put | Rollback)\n}","tryCatchPattern":null,"preventionTips":["Run log-backup compaction on a staging copy of the segment first and watch for `encountering two different values` warnings","Keep backup-producing and compacting TiKV versions aligned so write records follow known shapes","Monitor logs for the warn! in SubcompactionExec::resolve — it precedes the panic","Never manually edit or partially restore backup SST files"],"tags":["rust","log-backup","compaction","panic"],"backgroundTag":"unresolvable-compaction-conflict","analyzedSha":"78aedc1c81ef3f7d8bacc6e9d09f56460f134937","analyzedAt":"2026-09-03T23:31:32.398Z","contentChangedAt":"2026-09-03T23:31:32.398Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}