{"record":{"id":"380503b1d6ffd567","repo":"risingwavelabs/risingwave","slug":"frame-starting-from-current-row-cannot-have-preced","errorCode":null,"errorMessage":"frame starting from current row cannot have preceding rows","messagePattern":"frame starting from current row cannot have preceding rows","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/core/src/window_function/call.rs","lineNumber":227,"sourceCode":"            Preceding(offset) | Following(offset) => Some(offset),\n        }\n    }\n\n    pub(super) fn validate_bounds(\n        start: &Self,\n        end: &Self,\n        offset_checker: impl Fn(&T) -> Result<()>,\n    ) -> Result<()> {\n        match (start, end) {\n            (_, UnboundedPreceding) => bail!(\"frame end cannot be UNBOUNDED PRECEDING\"),\n            (UnboundedFollowing, _) => {\n                bail!(\"frame start cannot be UNBOUNDED FOLLOWING\")\n            }\n            (Following(_), CurrentRow) | (Following(_), Preceding(_)) => {\n                bail!(\"frame starting from following row cannot have preceding rows\")\n            }\n            (CurrentRow, Preceding(_)) => {\n                bail!(\"frame starting from current row cannot have preceding rows\")\n            }\n            _ => {}\n        }\n\n        for bound in [start, end] {\n            if let Some(offset) = bound.offset_value() {\n                offset_checker(offset)?;\n            }\n        }\n\n        Ok(())\n    }\n\n    pub fn map<U>(self, f: impl Fn(T) -> U) -> FrameBound<U> {\n        match self {\n            UnboundedPreceding => UnboundedPreceding,\n            Preceding(offset) => Preceding(f(offset)),\n            CurrentRow => CurrentRow,","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/core/src/window_function/call.rs#L209-L245","documentation":"During window frame bound validation, a frame starting at CURRENT ROW is not allowed to end at a Preceding row, since the end would be before the start. validate_bounds rejects this contradictory frame specification.","triggerScenarios":"Constructing a WindowFuncCall with frame bounds start=CurrentRow and end=Preceding(n), e.g. SQL `ROWS BETWEEN CURRENT ROW AND 3 PRECEDING`.","commonSituations":"User SQL with reversed frame direction (author intended FOLLOWING), or programmatic frame construction that mixes up preceding/following semantics.","solutions":["Rewrite the frame as `BETWEEN n PRECEDING AND CURRENT ROW` to scan backwards.","Use `BETWEEN CURRENT ROW AND n FOLLOWING` if forward-looking rows were intended.","Verify planner/frontend code that emits PbFrameBound pairs does not reverse start/end."],"exampleFix":"-- before\nSELECT sum(x) OVER (ORDER BY ts ROWS BETWEEN CURRENT ROW AND 3 PRECEDING) FROM t;\n-- after\nSELECT sum(x) OVER (ORDER BY ts ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) FROM t;","handlingStrategy":"validation","validationCode":"fn frame_bounds_valid(start: &Bound, end: &Bound) -> bool {\n    !matches!((start, end), (Bound::CurrentRow, Bound::Preceding(_)))\n}","typeGuard":"fn is_current_row_start(b: &Bound) -> bool { matches!(b, Bound::CurrentRow) }","tryCatchPattern":null,"preventionTips":["Normalize reversed frames to PRECEDING..CURRENT ROW form at parse time.","Document that frame start must not be after frame end.","Add frontend binder checks before building the protobuf plan."],"tags":["window-function","frame-bounds","sql","validation"],"backgroundTag":"invalid-argument-value","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"}