risingwavelabs/risingwave · error

corrupt MATCH_RECOGNIZE state row: seq column must be a non-

Error message

corrupt MATCH_RECOGNIZE state row: seq column must be a non-null int64, got {other:?}

What it means

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.

Source

Thrown at src/stream/src/executor/match_recognize/executor.rs:1104

                .iter_keyed_row_with_vnode(
                    vnode,
                    &(
                        std::ops::Bound::<OwnedRow>::Unbounded,
                        std::ops::Bound::<OwnedRow>::Unbounded,
                    ),
                    Default::default(),
                )
                .await?;
            pin_mut!(stream);
            while let Some(kv) = stream.next().await {
                let kv = kv?;
                let stored = kv.row();
                // Stored layout: `[ seq, <input cols..> ]`. Fail descriptive on a corrupt row —
                // a panic here would crash-loop recovery on state that recovery cannot fix.
                let seq = match stored.datum_at(0) {
                    Some(ScalarRefImpl::Int64(s)) => s,
                    other => {
                        return Err(anyhow::anyhow!(
                            "corrupt MATCH_RECOGNIZE state row: seq column must be a non-null \
                             int64, got {other:?}"
                        )
                        .into());
                    }
                };
                max_seq = max_seq.max(seq);
                let input_row = OwnedRow::new(
                    (1..stored.len())
                        .map(|i| stored.datum_at(i).to_owned_datum())
                        .collect(),
                );
                let pk = (&input_row).project(partition_key_indices).into_owned_row();
                let order_key = input_row.datum_at(time_col).to_owned_datum();
                // Not counted here: the ingest path counted this row once already, and a rebuild
                // re-evaluates every retained row on each recovery.
                let deadline = eval_deadline(within_deadline, &order_key).await;
                let run = parts.entry(pk).or_insert_with(|| PartitionRun {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Drop and recreate the MATCH_RECOGNIZE materialization/table so state is rebuilt from scratch, since recovery cannot fix a corrupt row
  2. 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
  3. Inspect the offending state row (the error logs `got {other:?}`) to confirm null vs wrong-type, and look for corresponding storage/Hummock corruption reports
  4. 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

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// Before recovery, sanity-check the state row's seq column
fn validate_seq_column(row: &[Datum]) -> Result<(), String> {
    match row.first() {
        Some(Some(ScalarImpl::Int64(_))) => Ok(()),
        other => Err(format!("MATCH_RECOGNIZE state seq column invalid: {other:?}")),
    }
}

Type guard

fn is_valid_seq(d: &Datum) -> bool {
    matches!(d, Some(ScalarImpl::Int64(_)))
}

Try / catch

match executor_result {
    Err(e) if e.to_string().contains("corrupt MATCH_RECOGNIZE state row") => {
        // Recovery cannot repair this state: drop and recreate the table/job
        recreate_match_recognize_job();
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/55bdfc70d7fbb633. Report an issue: GitHub.