risingwavelabs/risingwave · error
MATCH_RECOGNIZE plan carries an empty ORDER BY
Error message
MATCH_RECOGNIZE plan carries an empty ORDER BY
What it means
The MATCH_RECOGNIZE executor unconditionally reads the leading ORDER BY column to establish event-time ordering, so an empty ORDER BY list would cause an index panic later. `new_boxed_executor` validates the decoded `order_key_indices` and returns this error instead, treating an empty ORDER BY as a corrupt plan fragment.
Source
Thrown at src/stream/src/from_proto/match_recognize.rs:91
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()))
.collect::<crate::executor::StreamExecutorResult<Vec<_>>>()?;
let measures = node
.measures
.iter()
.map(|m| CompiledMeasure::from_protobuf(m, params.eval_error_report.clone()))
.collect::<crate::executor::StreamExecutorResult<Vec<_>>>()?;
let pattern_node = node
.pattern_node
.as_ref()
.ok_or_else(|| anyhow::anyhow!("MATCH_RECOGNIZE node missing pattern"))?;
let pattern = pattern_from_protobuf(pattern_node)View on GitHub (pinned to 6469eb736d)
Solutions
- Ensure the query includes a required ORDER BY clause in MATCH_RECOGNIZE, e.g. `ORDER BY event_time`.
- Fix the frontend so it always emits a non-empty `order_by` (event time ordering is mandatory).
- Re-plan/re-create the streaming job with matching frontend and compute versions.
- In tests, populate `order_by` with at least one column index before building the executor.
Example fix
// before
let node = MatchRecognizeNode { order_by: vec![], .. };
// after
let node = MatchRecognizeNode { order_by: vec![column_order(0, OrderType::ascending())], .. }; Defensive patterns
Strategy: validation
Validate before calling
// before constructing the executor
if order_key_indices.is_empty() {
return Err(anyhow!("MATCH_RECOGNIZE plan carries an empty ORDER BY"));
} Type guard
fn first_order_column(order_by: &[ColumnOrder]) -> Option<usize> { order_by.first().map(|c| c.column_index) } Try / catch
let ts_idx = order_key_indices.first().copied().ok_or_else(|| anyhow!("MATCH_RECOGNIZE plan carries an empty ORDER BY"))?; Prevention
- Always include ORDER BY in MATCH_RECOGNIZE queries.
- Add a frontend invariant test: emitted MATCH_RECOGNIZE nodes have >= 1 order column.
- Validate plan protos when deserializing actors, not only at executor build time.
When it happens
Trigger: `new_boxed_executor` decodes `node.order_by` into an empty `Vec<usize>` — the plan proto carried no ORDER BY entries for the MATCH_RECOGNIZE node (missing field, planner bug, or hand-trimmed proto).
Common situations: Version skew where the frontend omitted the mandatory ORDER BY; corrupted plan fragments; tests constructing MATCH_RECOGNIZE nodes without setting `order_by`.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- MATCH_RECOGNIZE node missing pattern
- IcebergWithPkIndexWriterExecutor requires exactly two inputs
- missing downstream pk in iceberg sink desc
- unknown MATCH_RECOGNIZE input mode: {}
- unsupported MATCH_RECOGNIZE input mode: {other:?}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/e705ab3eb7df08cf.
Report an issue: GitHub.