risingwavelabs/risingwave · error

MATCH_RECOGNIZE ORDER BY column

Error message

MATCH_RECOGNIZE ORDER BY column {} is out of range for an input of {} columns

What it means

The executor reads the ORDER BY column index from the plan and looks it up in the input schema to get the ordering column's type. The index exceeds the number of input columns, so the schema lookup fails. This means the plan's order key index is inconsistent with the input schema — a corrupt plan or schema skew.

Solutions

  1. Re-create the streaming job (drop and re-issue the CREATE MATERIALIZED VIEW) so plan and schema are rebuilt together.
  2. Align node versions across the cluster to rule out version skew.
  3. Inspect the plan (EXPLAIN) and confirm the ORDER BY column exists on the input relation.
  4. If reproducible, report a planner bug — indices and schema should always agree.
Defensive patterns

Strategy: validation

Validate before calling

// Check the order key index is in bounds before building the executor
fn order_key_in_bounds(idx: usize, schema_len: usize) -> bool {
    idx < schema_len
}

Try / catch

// Bounds-check defensively and log plan vs schema
let idx = order_key_indices[0];
if idx >= input.schema().len() {
    return Err(anyhow!("ORDER BY index {idx} out of range for schema len {}", input.schema().len()));
}

Prevention

When it happens

Trigger: `new_boxed_executor` receives a MatchRecognizeNode whose `order_key_indices[0]` is >= `input.schema().len()` — e.g. the upstream operator was rewritten to fewer columns while the plan still references the old index.

Common situations: Version skew where a plan built against an older schema is replayed on a newer executor; corrupt plan persistence; plan fragments changed by a manual DDL/evolution while the MV plan was not refreshed.

Related errors


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

Appendix: source

Thrown at src/stream/src/from_proto/match_recognize.rs:184

            return Err(anyhow::anyhow!(
                "MATCH_RECOGNIZE carries only one of the two WITHIN expressions \
                 (predicate: {}, deadline: {}); the binder emits both or neither",
                within.is_some(),
                within_deadline.is_some(),
            )
            .into());
        }
        // The deadline is compared directly against the order key and the watermark
        // (`ScalarRefImpl::default_cmp` panics across variants — an actor crash loop that recovery
        // replays), and the span predicate is a boolean. The binder guarantees both
        // (`lower_within`); re-state it here so a skewed or corrupt plan fails at build time.
        let order_key_type = input
            .schema()
            .fields
            .get(order_key_indices[0])
            .map(|f| f.data_type())
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "MATCH_RECOGNIZE ORDER BY column {} is out of range for an input of {} columns",
                    order_key_indices[0],
                    input.schema().len()
                )
            })?;
        if let Some(deadline) = &within_deadline
            && deadline.return_type() != order_key_type
        {
            return Err(anyhow::anyhow!(
                "MATCH_RECOGNIZE WITHIN deadline has type {} but the ORDER BY column has type {}; \
                 the two are compared directly",
                deadline.return_type(),
                order_key_type,
            )
            .into());
        }
        if let Some(predicate) = &within
            && predicate.return_type() != DataType::Boolean

View on GitHub (pinned to 6469eb736d)