risingwavelabs/risingwave · error
invalid MATCH_RECOGNIZE measure slot kind: {}
Error message
invalid MATCH_RECOGNIZE measure slot kind: {} What it means
A MATCH_RECOGNIZE measure slot's protobuf `kind` field decoded to UNSPECIFIED, meaning the wire value was unset or out of range. Since every later match on the kind relies on it being a concrete aggregation kind, the executor rejects it at deserialization instead of silently changing measure semantics.
Source
Thrown at src/stream/src/executor/match_recognize/executor.rs:206
pb: &PbMatchRecognizeMeasure,
error_report: impl EvalErrorReport + 'static,
) -> StreamExecutorResult<Self> {
let expr = build_non_strict_from_prost(
pb.expr
.as_ref()
.ok_or_else(|| anyhow::anyhow!("MATCH_RECOGNIZE measure missing expression"))?,
error_report,
)?;
let slots = pb
.slots
.iter()
.map(|s| {
let kind = s.kind();
// Fail fast rather than silently changing measure semantics under a corrupt plan
// or version skew. (An out-of-range wire value decodes as UNSPECIFIED via
// `s.kind()`.) Every later match on the kind relies on this rejection.
if kind == MeasureSlotKind::Unspecified {
return Err(anyhow::anyhow!(
"invalid MATCH_RECOGNIZE measure slot kind: {}",
s.kind
)
.into());
}
let agg = match kind {
MeasureSlotKind::Sum => {
let call =
AggCall::from_protobuf(s.agg_call.as_ref().ok_or_else(|| {
anyhow::anyhow!(
"MATCH_RECOGNIZE SUM/AVG measure slot missing agg_call"
)
})?)?;
let col_type = call.args.arg_types()[0].clone();
let func = build_append_only(&call)?;
Some(AggSlot { func, col_type })
}
_ => None,View on GitHub (pinned to 6469eb736d)
Solutions
- Align frontend and backend versions so all MeasureSlotKind values are recognized.
- Re-create the streaming job to regenerate a valid plan.
- In test code, always set a valid kind (Sum/Avg/etc.) on measure slots.
Example fix
// before
PbMeasureSlot { kind: 99 } // out of range -> UNSPECIFIED
// after
PbMeasureSlot { kind: MeasureSlotKind::Sum as i32 } Defensive patterns
Strategy: validation
Validate before calling
// Check the kind decodes to a known value before use:
let kind = s.kind();
if kind == MeasureSlotKind::Unspecified {
return Err(anyhow!("unsupported measure slot kind {}", s.kind));
} Try / catch
// Catch enum rejection during plan load and regenerate the plan:
match slot_from_protobuf(&pb) {
Err(e) if e.to_string().contains("invalid MATCH_RECOGNIZE measure slot kind") => regenerate_plan(),
r => r,
} Prevention
- Keep protobuf enum definitions in sync between frontend and backend.
- Never send hand-picked integer kind values; use the enum's as-i32 conversion.
- Test plans through real serialization round-trips.
When it happens
Trigger: MeasureSlot::from_protobuf sees s.kind() == MeasureSlotKind::Unspecified, e.g. an out-of-range i32 in the kind field or kind simply not set.
Common situations: Version skew: newer frontend emits a kind value the older backend doesn't know; corrupt plan in meta storage; hand-built prost messages in tests.
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
- invalid MATCH_RECOGNIZE define slot kind: {}
- MATCH_RECOGNIZE measure missing expression
- MATCH_RECOGNIZE SUM/AVG measure slot missing agg_call
- MATCH_RECOGNIZE define missing condition
- invalid MATCH_RECOGNIZE after_match_skip mode: {}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/11dc8ad923a13ce9.
Report an issue: GitHub.