risingwavelabs/risingwave · error

MATCH_RECOGNIZE define missing condition

Error message

MATCH_RECOGNIZE define missing condition

What it means

When deserializing a MATCH_RECOGNIZE DEFINE slot from protobuf, the condition expression (`pb.condition`) is absent. Each DEFINE row pattern needs a concrete boolean condition to evaluate candidates, so the executor fails deserialization rather than building a define that matches everything.

Source

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

    offset: usize,
}

/// A `DEFINE` predicate compiled for execution: a boolean condition over a synthetic slot row.
pub struct CompiledDefine {
    symbol: String,
    condition: NonStrictExpression,
    slots: Vec<DefineSlot>,
}

impl CompiledDefine {
    pub fn from_protobuf(
        pb: &PbMatchRecognizeDefine,
        error_report: impl EvalErrorReport + 'static,
    ) -> StreamExecutorResult<Self> {
        let condition = build_non_strict_from_prost(
            pb.condition
                .as_ref()
                .ok_or_else(|| anyhow::anyhow!("MATCH_RECOGNIZE define missing condition"))?,
            error_report,
        )?;
        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"
                    )));
                }

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Re-create the query/MV so the frontend regenerates a complete plan.
  2. Check for version skew between frontend and stream compute and upgrade consistently.
  3. When crafting protobufs in tests, always set condition on DEFINE slots.

Example fix

// before
PbMatchRecognizeDefine { slots: ..., condition: None }
// after
PbMatchRecognizeDefine { slots: ..., condition: Some(condition_proto) }
Defensive patterns

Strategy: validation

Validate before calling

// Validate before building the define slot:
if define.condition.is_none() {
    return Err(anyhow!("DEFINE '{}' has no condition", define.pattern));
}

Try / catch

// Catch missing-condition at plan load and regenerate:
match DefineSlot::from_protobuf(&pb, &report) {
    Err(e) if e.to_string().contains("define missing condition") => re_plan_or_recreate_job(),
    r => r,
}

Prevention

When it happens

Trigger: DefineSlot::from_protobuf called with a PbMatchRecognizeDefine whose condition field is None.

Common situations: Corrupt or hand-edited plan protobuf; frontend/backend version skew losing the field; manually built prost messages in tests.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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