{"record":{"id":"20c4900d6c8108cb","repo":"risingwavelabs/risingwave","slug":"session-frame-gap-add-expression-must-be-sync","errorCode":null,"errorMessage":"session frame gap add expression must be sync","messagePattern":"session frame gap add expression must be sync","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/core/src/window_function/session.rs","lineNumber":172,"sourceCode":"    pub fn new(gap: ScalarImpl) -> Self {\n        Self {\n            gap,\n            add_expr: None,\n        }\n    }\n\n    fn prepare(&mut self, order_data_type: &DataType, gap_data_type: &DataType) -> Result<()> {\n        use risingwave_pb::expr::expr_node::PbType as PbExprType;\n\n        let input_expr = InputRefExpression::new(order_data_type.clone(), 0);\n        let gap_expr = LiteralExpression::new(gap_data_type.clone(), Some(self.gap.clone()));\n        let add_expr = build_func(\n            PbExprType::Add,\n            order_data_type.clone(),\n            vec![input_expr.boxed(), gap_expr.boxed()],\n        )?;\n        let crate::expr::BoxedExpression::Sync(add_expr) = add_expr else {\n            bail!(\"session frame gap add expression must be sync\");\n        };\n        self.add_expr = Some(add_expr);\n        Ok(())\n    }\n\n    pub fn new_for_test(\n        gap: ScalarImpl,\n        order_data_type: &DataType,\n        gap_data_type: &DataType,\n    ) -> Self {\n        let mut gap = Self::new(gap);\n        gap.prepare(order_data_type, gap_data_type).unwrap();\n        gap\n    }\n\n    fn for_calc(&self) -> SessionFrameGapRef<'_> {\n        SessionFrameGapRef {\n            add_expr: self.add_expr.as_ref().unwrap().as_ref(),","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/core/src/window_function/session.rs#L154-L190","documentation":"Session frame construction builds an Add expression (`order_col + gap`) used to compute the session end per row. Like the RANGE frame path, the session executor only supports synchronous expressions, so the built Add must be the `BoxedExpression::Sync` variant; otherwise construction fails.","triggerScenarios":"`SessionFrameBounds::prepare` during `from_protobuf` where the Add expression over the order column and gap compiles to a non-sync (e.g. async) expression variant.","commonSituations":"New data types or expression kinds lacking a sync eval implementation; frontend/backend version mismatch so the builder wraps Add in an unexpected variant.","solutions":["Ensure the Add expression implementation for the order column type builds a Sync variant","Check `build_func` dispatch for the affected type and add a sync constructor if missing","Align frontend and backend versions"],"exampleFix":"// before: non-sync Add built by builder\nlet add_expr = build_func(PbExprType::Add, order_data_type, vec![input_expr.boxed(), gap_expr.boxed()])?;\n// after: guarantee Sync variant from the constructor\nlet crate::expr::BoxedExpression::Sync(add_expr) = add_expr else {\n    bail!(\"session frame gap add expression must be sync\");\n};","handlingStrategy":"try-catch","validationCode":"fn ensure_add_sync(e: &BoxedExpression) -> Result<()> {\n    if !matches!(e, BoxedExpression::Sync(_)) { bail!(\"session add expr not sync\"); }\n    Ok(())\n}","typeGuard":"fn is_sync(e: &BoxedExpression) -> bool { matches!(e, BoxedExpression::Sync(_)) }","tryCatchPattern":"match SessionFrameBounds::from_protobuf(&pb) {\n    Err(e) if e.to_string().contains(\"must be sync\") => report_or_fallback(e),\n    other => other,\n}","preventionTips":["Ensure Add for all order-column types builds Sync expressions","Add compile-time/test coverage per data type","Keep frontend/backend versions aligned"],"tags":["rust","window-function","session-window","expression-serialization"],"backgroundTag":"internal-invariant-violation","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"}