{"record":{"id":"800895b5cab770f2","repo":"risingwavelabs/risingwave","slug":"after-match-skip-to-first-last-missing-its-target","errorCode":null,"errorMessage":"AFTER MATCH SKIP TO FIRST/LAST missing its target variable","messagePattern":"AFTER MATCH SKIP TO FIRST/LAST missing its target variable","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/from_proto/match_recognize.rs","lineNumber":123,"sourceCode":"        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,\n                Mode::ToFirst => SkipMode::ToFirst(target()?),\n                Mode::ToLast => SkipMode::ToLast(target()?),\n                Mode::Unspecified => {\n                    return Err(anyhow::anyhow!(\n                        \"invalid MATCH_RECOGNIZE after_match_skip mode: {}\",\n                        pb_skip.mode\n                    )\n                    .into());\n                }\n            }\n        };\n\n        let within = node","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/from_proto/match_recognize.rs#L105-L141","documentation":"When the plan requests `AFTER MATCH SKIP TO FIRST <var>` or `TO LAST <var>`, the proto must carry a `target` variable naming the row to skip to. The decoder found a TO FIRST/TO LAST skip mode with no target variable and rejects the plan. Without the target the skip semantics are undefined, so the executor fails loudly.","triggerScenarios":"`new_boxed_executor` decodes a MatchRecognizeNode whose `after_match_skip.mode` is `ToFirst` or `ToLast` while `after_match_skip.target` is `None`.","commonSituations":"Version skew where the producer did not yet serialize the target field; corrupted or hand-built plan protos; frontend emitting TO FIRST/LAST without a variable (a frontend bug).","solutions":["Check the SQL: `AFTER MATCH SKIP TO FIRST/LAST` must name a pattern variable, e.g. `SKIP TO LAST b`.","Re-create the streaming job so the plan is regenerated by the current binder.","Align cluster node versions (restart meta and compute nodes).","If the SQL is valid and this persists, report a binder/proto bug."],"exampleFix":"// before (SQL)\nAFTER MATCH SKIP TO LAST\n// after\nAFTER MATCH SKIP TO LAST b","handlingStrategy":"validation","validationCode":"// SQL-level check: TO FIRST/LAST must name a variable\n-- validate: pattern has variable v and clause reads SKIP TO FIRST v / SKIP TO LAST v","typeGuard":null,"tryCatchPattern":"// Validate mode/target pairing before executor construction\nfn validate_skip(skip: &AfterMatchSkip) -> Result<(), String> {\n    use Mode::*;\n    match skip.mode() {\n        ToFirst | ToLast if skip.target.is_none() => Err(\"TO FIRST/LAST requires target\".into()),\n        _ => Ok(()),\n    }\n}","preventionTips":["Always write `AFTER MATCH SKIP TO FIRST <var>` / `TO LAST <var>` with an explicit pattern variable.","Mirror standard SQL semantics: TO FIRST/LAST are meaningless without a target.","Add frontend tests asserting target is emitted for TO FIRST/TO LAST."],"tags":["streaming","match-recognize","missing-field","sql"],"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"}