{"record":{"id":"afdf3e968e23efe5","repo":"risingwavelabs/risingwave","slug":"the-window-frame-must-be-valid","errorCode":null,"errorMessage":"the window frame must be valid","messagePattern":"the window frame must be valid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/window_function/aggregate.rs","lineNumber":53,"sourceCode":"\nuse super::buffer::{RangeWindow, RowsWindow, SessionWindow, WindowBuffer, WindowImpl};\n\ntype StateValue = SmallVec<[Datum; 2]>;\n\nstruct AggregateState<W>\nwhere\n    W: WindowImpl<Key = StateKey, Value = StateValue>,\n{\n    agg_impl: AggImpl,\n    arg_data_types: Vec<DataType>,\n    ignore_nulls: bool,\n    buffer: WindowBuffer<W>,\n    buffer_heap_size: KvSize,\n}\n\npub(super) fn new(call: &WindowFuncCall) -> Result<BoxedWindowState> {\n    if call.frame.bounds.validate().is_err() {\n        bail!(\"the window frame must be valid\");\n    }\n    let agg_type = must_match!(&call.kind, WindowFuncKind::Aggregate(agg_type) => agg_type);\n    let arg_data_types = call.args.arg_types().to_vec();\n    let agg_call = AggCall {\n        agg_type: agg_type.clone(),\n        args: call.args.clone(),\n        return_type: call.return_type.clone(),\n        column_orders: Vec::new(), // the input is already sorted\n        // TODO(rc): support filter on window function call\n        filter: None,\n        // TODO(rc): support distinct on window function call? PG doesn't support it either.\n        distinct: false,\n        direct_args: vec![],\n    };\n\n    let (agg_impl, enable_delta) = match agg_type {\n        AggType::Builtin(PbAggKind::FirstValue) => (AggImpl::Shortcut(Shortcut::FirstValue), false),\n        AggType::Builtin(PbAggKind::LastValue) => (AggImpl::Shortcut(Shortcut::LastValue), false),","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/window_function/aggregate.rs#L35-L71","documentation":"When constructing the window aggregate state, RisingWave validates the frame bounds with `bounds.validate()`. If the bounds are invalid (e.g. malformed UNBOUNDED/offset combinations), construction is aborted because the aggregate would produce undefined results while sliding the frame.","triggerScenarios":"Creating an aggregate window function (WindowFuncKind::Aggregate) whose WindowFrameBounds fail `validate()` — e.g. a frame with invalid start/end ordering or an offset frame that is not permitted.","commonSituations":"A planner/frontend bug letting a malformed OVER clause through; manual construction of WindowFuncCall in tests; a frame like ROWS BETWEEN 2 FOLLOWING AND 1 PRECEDING.","solutions":["Fix the frontend/planner so only valid frames reach the executor","Correct the OVER clause frame specification in the query","Check `WindowFrameBounds::validate` logic if a legitimate frame is being rejected"],"exampleFix":"// before\nbail!(\"the window frame must be valid\");\n// after\nbail!(\"invalid window frame bounds: {:?}\", call.frame.bounds); // at minimum log which bounds failed","handlingStrategy":"validation","validationCode":"fn frame_is_valid(bounds: &WindowFrameBounds) -> bool { bounds.validate().is_ok() }","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"window frame must be valid\") => fix_or_reject_frame(query),\n    other => other?,\n}","preventionTips":["Only emit frames from the frontend after calling bounds.validate()","Add planner tests for offset FOLLOWING/PRECEDING combinations","Reject invalid OVER clauses at SQL parse/plan time"],"tags":["window-function","aggregate","frame"],"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-23T08:17:48.524Z"}