risingwavelabs/risingwave · error

MATCH_RECOGNIZE only supports the default ascending ORDER BY

Error message

MATCH_RECOGNIZE only supports the default ascending ORDER BY, got {:?}

What it means

MATCH_RECOGNIZE v1 supports only the default ascending ORDER BY on its event-time column. During decode, each ORDER BY entry is converted to a `ColumnOrder`; if any entry's `order_type` is not ascending, the executor refuses to build, since descending/other orderings are not implemented in the NFA event-time handling.

Source

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

            MatchRecognizeInputMode::Unspecified | MatchRecognizeInputMode::EventTime => {}
            other => {
                return Err(
                    anyhow::anyhow!("unsupported MATCH_RECOGNIZE input mode: {other:?}").into(),
                );
            }
        }

        let partition_key_indices = node.partition_by.iter().map(|&i| i as usize).collect();
        // ORDER BY is carried as `ColumnOrder`. v1 only supports the default ascending order (the
        // binder rejects anything else); assert it here too so a non-ascending plan fails fast
        // rather than being silently sorted ascending by the executor.
        let order_key_indices = node
            .order_by
            .iter()
            .map(|c| {
                let co = ColumnOrder::from_protobuf(c);
                if co.order_type != OrderType::ascending() {
                    return Err(anyhow::anyhow!(
                        "MATCH_RECOGNIZE only supports the default ascending ORDER BY, got {:?}",
                        co.order_type
                    )
                    .into());
                }
                Ok(co.column_index)
            })
            .collect::<StreamResult<Vec<usize>>>()?;
        // The executor reads the leading ORDER BY column unconditionally; an empty list is a
        // corrupt plan and must fail here, not index-panic there.
        if order_key_indices.is_empty() {
            return Err(anyhow::anyhow!("MATCH_RECOGNIZE plan carries an empty ORDER BY").into());
        }

        let defines = node
            .defines
            .iter()
            .map(|d| CompiledDefine::from_protobuf(d, params.eval_error_report.clone()))

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Rewrite the MATCH_RECOGNIZE ORDER BY to use ascending order (the default), e.g. `ORDER BY ts` not `ORDER BY ts DESC`.
  2. If reverse ordering is intended, invert the pattern logic instead of the sort direction.
  3. Check the frontend version and re-plan if an older planner emitted a non-ascending order type.
  4. Implement descending-order support in the executor if it becomes a product requirement.

Example fix

-- before
MATCH_RECOGNIZE ( ORDER BY ts DESC ... )
-- after
MATCH_RECOGNIZE ( ORDER BY ts ... )
Defensive patterns

Strategy: validation

Validate before calling

-- SQL guard: ascending-only ORDER BY inside MATCH_RECOGNIZE
MATCH_RECOGNIZE ( ORDER BY ts ASC ... ) -- never ORDER BY ts DESC

Type guard

fn is_ascending(co: &ColumnOrder) -> bool { co.order_type == OrderType::ascending() }

Try / catch

if co.order_type != OrderType::ascending() { return Err(anyhow!("MATCH_RECOGNIZE only supports the default ascending ORDER BY, got {:?}", co.order_type).into()); }

Prevention

When it happens

Trigger: `new_boxed_executor` decodes `node.order_by` and encounters a `ColumnOrder` whose `order_type` differs from `OrderType::ascending()` — e.g. the frontend emitted `ORDER BY ts DESC` inside MATCH_RECOGNIZE.

Common situations: Writing `MATCH_RECOGNIZE ( ORDER BY ts DESC ... )` in SQL; planner bugs emitting non-default order types; plan proto hand-editing or version skew introducing new order types.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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