{"record":{"id":"acf652bbaf663657","repo":"risingwavelabs/risingwave","slug":"invalid-match-recognize-pattern-e","errorCode":null,"errorMessage":"invalid MATCH_RECOGNIZE pattern: {e}","messagePattern":"invalid MATCH_RECOGNIZE pattern: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/from_proto/match_recognize.rs","lineNumber":110,"sourceCode":"        }\n\n        let defines = node\n            .defines\n            .iter()\n            .map(|d| CompiledDefine::from_protobuf(d, params.eval_error_report.clone()))\n            .collect::<crate::executor::StreamExecutorResult<Vec<_>>>()?;\n        let measures = node\n            .measures\n            .iter()\n            .map(|m| CompiledMeasure::from_protobuf(m, params.eval_error_report.clone()))\n            .collect::<crate::executor::StreamExecutorResult<Vec<_>>>()?;\n\n        let pattern_node = node\n            .pattern_node\n            .as_ref()\n            .ok_or_else(|| anyhow::anyhow!(\"MATCH_RECOGNIZE node missing pattern\"))?;\n        let pattern = pattern_from_protobuf(pattern_node)\n            .map_err(|e| anyhow::anyhow!(\"invalid MATCH_RECOGNIZE pattern: {e}\"))?;\n        let nfa = Nfa::compile(&pattern);\n\n        // Fail fast on anything malformed rather than silently defaulting to PAST LAST ROW, which\n        // would mask a corrupt plan or a version skew.\n        let skip = {\n            use risingwave_pb::stream_plan::match_recognize_after_match_skip::Mode;\n            let pb_skip = node\n                .after_match_skip\n                .as_ref()\n                .ok_or_else(|| anyhow::anyhow!(\"MATCH_RECOGNIZE node missing after_match_skip\"))?;\n            let target = || {\n                pb_skip.target.clone().ok_or_else(|| {\n                    anyhow::anyhow!(\"AFTER MATCH SKIP TO FIRST/LAST missing its target variable\")\n                })\n            };\n            match pb_skip.mode() {\n                Mode::PastLastRow => SkipMode::PastLastRow,\n                Mode::ToNextRow => SkipMode::ToNextRow,","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/from_proto/match_recognize.rs#L92-L128","documentation":"This error wraps a failure while decoding the MATCH_RECOGNIZE pattern from its protobuf representation into the in-memory pattern AST during stream executor construction. `pattern_from_protobuf` failed to convert the serialized pattern node (variables, concatenation, quantifiers, etc.), so the executor refuses to build. It exists to preserve the underlying parse/decode error context rather than panic.","triggerScenarios":"Calling `MatchRecognizeExecutor::new` (via `new_boxed_executor`) with a stream plan whose `pattern_node` is present but whose nested pattern proto fails `pattern_from_protobuf` — e.g. malformed pattern fields, unknown enum variants, or an incompatible proto schema version.","commonSituations":"Version skew between the meta node (plan producer) and stream node (plan consumer) after a rolling upgrade; a corrupt or hand-edited serialized plan; a newly added pattern construct understood by the binder/frontend but not yet by the older proto decoder on the compute node.","solutions":["Read the inner error text (the `{e}` part) to find which pattern element failed to decode.","Verify meta and stream node versions match; restart the cluster so all nodes run the same build.","Recreate or refresh the affected streaming job (e.g. ALTER/refresh the materialized view or re-issue the CREATE MATERIALIZED VIEW) so the plan is regenerated.","If reproducible, file a bug with the plan — a valid binder-produced pattern should always decode."],"exampleFix":"// before: opaque error\n.map_err(|e| anyhow::anyhow!(\"invalid MATCH_RECOGNIZE pattern: {e}\"))?\n// after: include the offending pattern for diagnosis\n.map_err(|e| anyhow::anyhow!(\"invalid MATCH_RECOGNIZE pattern {:?}: {e}\", pattern_node))?","handlingStrategy":"try-catch","validationCode":"// Before relying on the executor, sanity-check the pattern proto is present and well-formed\nfn pattern_valid(node: &MatchRecognizeNode) -> bool {\n    node.pattern_node.is_some()\n}","typeGuard":null,"tryCatchPattern":"// Rust: executor construction returns Result; surface the context, don't unwrap\nlet exec = MatchRecognizeExecutor::new(...).map_err(|e| {\n    tracing::error!(\"MATCH_RECOGNIZE executor build failed: {e:#}\");\n    e\n})?;","preventionTips":["Keep meta and compute nodes on the same version; avoid rolling upgrades across pattern-feature boundaries.","Always generate plans via the binder/frontend, never hand-craft protos.","Add round-trip tests: proto -> pattern -> proto for all supported MATCH_RECOGNIZE constructs."],"tags":["streaming","match-recognize","protobuf","plan-decoding"],"backgroundTag":"protobuf-unmarshal-failed","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"}