{"record":{"id":"adc9c382e0cbe203","repo":"risingwavelabs/risingwave","slug":"match-recognize-measure-missing-expression","errorCode":null,"errorMessage":"MATCH_RECOGNIZE measure missing expression","messagePattern":"MATCH_RECOGNIZE measure missing expression","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/match_recognize/executor.rs","lineNumber":194,"sourceCode":"}\n\n/// A `MEASURES` item compiled for execution.\npub struct CompiledMeasure {\n    /// Expression over the synthetic per-match row: `InputRef(i)` reads `slots[i]`.\n    expr: NonStrictExpression,\n    slots: Vec<MeasureSlot>,\n}\n\nimpl CompiledMeasure {\n    /// Builds a compiled measure from its protobuf, building any aggregate kernels its slots need.\n    pub fn from_protobuf(\n        pb: &PbMatchRecognizeMeasure,\n        error_report: impl EvalErrorReport + 'static,\n    ) -> StreamExecutorResult<Self> {\n        let expr = build_non_strict_from_prost(\n            pb.expr\n                .as_ref()\n                .ok_or_else(|| anyhow::anyhow!(\"MATCH_RECOGNIZE measure missing expression\"))?,\n            error_report,\n        )?;\n        let slots = pb\n            .slots\n            .iter()\n            .map(|s| {\n                let kind = s.kind();\n                // Fail fast rather than silently changing measure semantics under a corrupt plan\n                // or version skew. (An out-of-range wire value decodes as UNSPECIFIED via\n                // `s.kind()`.) Every later match on the kind relies on this rejection.\n                if kind == MeasureSlotKind::Unspecified {\n                    return Err(anyhow::anyhow!(\n                        \"invalid MATCH_RECOGNIZE measure slot kind: {}\",\n                        s.kind\n                    )\n                    .into());\n                }\n                let agg = match kind {","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/match_recognize/executor.rs#L176-L212","documentation":"When deserializing a MATCH_RECOGNIZE executor from its protobuf plan, a measure slot carries no expression (`pb.expr` is None). The executor requires every measure to be backed by a concrete expression to build its evaluator, so it fails the deserialization instead of building a measure that computes nothing.","triggerScenarios":"Calling MeasureSlot::from_protobuf with a PbMatchRecognizeMeasure whose expr field is unset/None.","commonSituations":"Corrupt or hand-edited plan fragments; protobuf produced by a frontend version mismatch where the field was expected to be filled; manually crafted prost messages in tests.","solutions":["Regenerate the plan: drop and re-create the query/MV so the frontend emits a complete protobuf.","Check frontend/backend version consistency; upgrade so both sides understand MATCH_RECOGNIZE measures.","If writing a test or tool, always populate the expr field on PbMatchRecognizeMeasure."],"exampleFix":"// before\nlet pb = PbMatchRecognizeMeasure { slots: ..., expr: None };\n// after\nlet pb = PbMatchRecognizeMeasure { slots: ..., expr: Some(expr_proto) };","handlingStrategy":"validation","validationCode":"// Validate before building the executor from protobuf:\nif measure.expr.is_none() {\n    return Err(anyhow!(\"measure '{}' has no expression\", measure.name));\n}","typeGuard":null,"tryCatchPattern":"// Match on deserialization failure and fall back to re-planning:\nmatch MeasureSlot::from_protobuf(&pb, &report) {\n    Err(e) if e.to_string().contains(\"missing expression\") => re_plan_or_recreate_job(),\n    r => r,\n}","preventionTips":["Always construct MATCH_RECOGNIZE plans through the standard frontend.","In tests, use builder helpers that enforce expr is Some.","Pin frontend and backend to the same version."],"tags":["match-recognize","protobuf","plan-deserialization"],"backgroundTag":"missing-required-argument","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}