risingwavelabs/risingwave · error

invalid MATCH_RECOGNIZE define slot kind: {}

Error message

invalid MATCH_RECOGNIZE define slot kind: {}

What it means

A MATCH_RECOGNIZE DEFINE slot's protobuf `kind` decoded to UNSPECIFIED (unset or out-of-range wire value). The executor fails fast because every later match on the kind relies on it being concrete; silently defaulting would change the predicate's meaning.

Source

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

        )?;
        let slots = pb
            .slots
            .iter()
            .map(|s| {
                let kind = s.kind();
                // The binder rejects physical NEXT in DEFINE (a verdict depending on rows after
                // the candidate needs per-candidate decidability), so no plan this frontend
                // produces carries it — reject rather than evaluate a watermark-unsafe,
                // arrival-order-dependent read from a skewed plan. UNSPECIFIED (also what an
                // out-of-range wire value decodes to) fails fast rather than silently changing
                // the predicate's meaning. Every later match on the kind relies on this.
                if kind == DefineSlotKind::Next {
                    return Err(StreamExecutorError::from(anyhow::anyhow!(
                        "physical NEXT in a MATCH_RECOGNIZE DEFINE is not supported"
                    )));
                }
                if kind == DefineSlotKind::Unspecified {
                    return Err(StreamExecutorError::from(anyhow::anyhow!(
                        "invalid MATCH_RECOGNIZE define slot kind: {}",
                        s.kind
                    )));
                }
                Ok(DefineSlot {
                    kind,
                    vars: s.vars.clone(),
                    col_idx: s.col_idx as usize,
                    offset: s.offset as usize,
                })
            })
            .collect::<StreamExecutorResult<Vec<_>>>()?;
        Ok(CompiledDefine {
            symbol: pb.symbol.clone(),
            condition,
            slots,
        })
    }

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Align frontend/backend versions so all DefineSlotKind values are understood.
  2. Re-create the streaming job to regenerate a valid plan.
  3. In tests, set a valid, supported kind on each define slot.

Example fix

// before
PbDefineSlot { kind: 42 } // out of range -> UNSPECIFIED
// after
PbDefineSlot { kind: DefineSlotKind::Expr as i32, .. }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the kind is a known, supported value before deserialization:
let kind = s.kind();
if kind == DefineSlotKind::Unspecified {
    return Err(anyhow!("unsupported define slot kind {}", s.kind));
}

Try / catch

// Regenerate the plan when an unknown enum value is rejected:
match define_from_protobuf(&pb) {
    Err(e) if e.to_string().contains("invalid MATCH_RECOGNIZE define slot kind") => regenerate_plan(),
    r => r,
}

Prevention

When it happens

Trigger: DefineSlot::from_protobuf sees kind == DefineSlotKind::Unspecified, typically from an out-of-range i32 kind value or a kind field left unset.

Common situations: Version skew where a newer frontend emits a kind the backend doesn't know; corrupt plan; hand-written prost messages missing the kind.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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