{"record":{"id":"55bdfc70d7fbb633","repo":"risingwavelabs/risingwave","slug":"corrupt-match-recognize-state-row-seq-column-must","errorCode":null,"errorMessage":"corrupt MATCH_RECOGNIZE state row: seq column must be a non-null int64, got {other:?}","messagePattern":"corrupt MATCH_RECOGNIZE state row: seq column must be a non-null int64, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/match_recognize/executor.rs","lineNumber":1104,"sourceCode":"                .iter_keyed_row_with_vnode(\n                    vnode,\n                    &(\n                        std::ops::Bound::<OwnedRow>::Unbounded,\n                        std::ops::Bound::<OwnedRow>::Unbounded,\n                    ),\n                    Default::default(),\n                )\n                .await?;\n            pin_mut!(stream);\n            while let Some(kv) = stream.next().await {\n                let kv = kv?;\n                let stored = kv.row();\n                // Stored layout: `[ seq, <input cols..> ]`. Fail descriptive on a corrupt row —\n                // a panic here would crash-loop recovery on state that recovery cannot fix.\n                let seq = match stored.datum_at(0) {\n                    Some(ScalarRefImpl::Int64(s)) => s,\n                    other => {\n                        return Err(anyhow::anyhow!(\n                            \"corrupt MATCH_RECOGNIZE state row: seq column must be a non-null \\\n                             int64, got {other:?}\"\n                        )\n                        .into());\n                    }\n                };\n                max_seq = max_seq.max(seq);\n                let input_row = OwnedRow::new(\n                    (1..stored.len())\n                        .map(|i| stored.datum_at(i).to_owned_datum())\n                        .collect(),\n                );\n                let pk = (&input_row).project(partition_key_indices).into_owned_row();\n                let order_key = input_row.datum_at(time_col).to_owned_datum();\n                // Not counted here: the ingest path counted this row once already, and a rebuild\n                // re-evaluates every retained row on each recovery.\n                let deadline = eval_deadline(within_deadline, &order_key).await;\n                let run = parts.entry(pk).or_insert_with(|| PartitionRun {","sourceCodeStart":1086,"sourceCodeEnd":1122,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/match_recognize/executor.rs#L1086-L1122","documentation":"MATCH_RECOGNIZE persists its pattern-matching state rows in a `[seq, <input columns>]` layout, where the first column is a monotonically increasing int64 sequence number. During state recovery the executor reads that column and throws this error if it is null or any type other than Int64. It is deliberately a descriptive error instead of a panic because a panic would crash-loop recovery forever on state that recovery cannot repair.","triggerScenarios":"State-table corruption or an incompatible schema version for the MATCH_RECOGNIZE state table: recovery reads a row whose column 0 is NULL, or was written by a different (older/newer) executor version that stored the sequence in another position/type, or manual state-table edits/restore produced a malformed row.","commonSituations":"Restoring a cluster from a snapshot/backup taken across a RisingWave version upgrade that changed the MATCH_RECOGNIZE state layout; interrupted state migrations; corrupted Hummock state due to storage-layer issues; users manually inspecting/mutating internal state tables.","solutions":["Drop and recreate the MATCH_RECOGNIZE materialization/table so state is rebuilt from scratch, since recovery cannot fix a corrupt row","Check whether the cluster was restored from a backup made by an incompatible RisingWave version; restore from a backup made by the same version instead","Inspect the offending state row (the error logs `got {other:?}`) to confirm null vs wrong-type, and look for corresponding storage/Hummock corruption reports","File an issue with RisingWave including the full error and the actor/state-table id; this is an internal invariant failure, not user-fixable data"],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"// Before recovery, sanity-check the state row's seq column\nfn validate_seq_column(row: &[Datum]) -> Result<(), String> {\n    match row.first() {\n        Some(Some(ScalarImpl::Int64(_))) => Ok(()),\n        other => Err(format!(\"MATCH_RECOGNIZE state seq column invalid: {other:?}\")),\n    }\n}","typeGuard":"fn is_valid_seq(d: &Datum) -> bool {\n    matches!(d, Some(ScalarImpl::Int64(_)))\n}","tryCatchPattern":"match executor_result {\n    Err(e) if e.to_string().contains(\"corrupt MATCH_RECOGNIZE state row\") => {\n        // Recovery cannot repair this state: drop and recreate the table/job\n        recreate_match_recognize_job();\n    }\n    other => other?,\n}","preventionTips":["Never restore state snapshots across RisingWave versions without a supported migration path","Do not manually edit internal state tables","Monitor for prior storage/Hummock errors that may have corrupted rows","Test disaster-recovery restore procedures on MATCH_RECOGNIZE jobs in staging"],"tags":["rust","streaming","state-corruption","recovery"],"backgroundTag":"schema-validation-failed","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}