risingwavelabs/risingwave · error

session frame gap add expression must be sync

Error message

session frame gap add expression must be sync

What it means

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.

Solutions

  1. Ensure the Add expression implementation for the order column type builds a Sync variant
  2. Check `build_func` dispatch for the affected type and add a sync constructor if missing
  3. Align frontend and backend versions

Example fix

// before: non-sync Add built by builder
let add_expr = build_func(PbExprType::Add, order_data_type, vec![input_expr.boxed(), gap_expr.boxed()])?;
// after: guarantee Sync variant from the constructor
let crate::expr::BoxedExpression::Sync(add_expr) = add_expr else {
    bail!("session frame gap add expression must be sync");
};
Defensive patterns

Strategy: try-catch

Validate before calling

fn ensure_add_sync(e: &BoxedExpression) -> Result<()> {
    if !matches!(e, BoxedExpression::Sync(_)) { bail!("session add expr not sync"); }
    Ok(())
}

Type guard

fn is_sync(e: &BoxedExpression) -> bool { matches!(e, BoxedExpression::Sync(_)) }

Try / catch

match SessionFrameBounds::from_protobuf(&pb) {
    Err(e) if e.to_string().contains("must be sync") => report_or_fallback(e),
    other => other,
}

Prevention

When it happens

Trigger: `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.

Common situations: New data types or expression kinds lacking a sync eval implementation; frontend/backend version mismatch so the builder wraps Add in an unexpected variant.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/20c4900d6c8108cb. Report an issue: GitHub.

Appendix: source

Thrown at src/expr/core/src/window_function/session.rs:172

    pub fn new(gap: ScalarImpl) -> Self {
        Self {
            gap,
            add_expr: None,
        }
    }

    fn prepare(&mut self, order_data_type: &DataType, gap_data_type: &DataType) -> Result<()> {
        use risingwave_pb::expr::expr_node::PbType as PbExprType;

        let input_expr = InputRefExpression::new(order_data_type.clone(), 0);
        let gap_expr = LiteralExpression::new(gap_data_type.clone(), Some(self.gap.clone()));
        let add_expr = build_func(
            PbExprType::Add,
            order_data_type.clone(),
            vec![input_expr.boxed(), gap_expr.boxed()],
        )?;
        let crate::expr::BoxedExpression::Sync(add_expr) = add_expr else {
            bail!("session frame gap add expression must be sync");
        };
        self.add_expr = Some(add_expr);
        Ok(())
    }

    pub fn new_for_test(
        gap: ScalarImpl,
        order_data_type: &DataType,
        gap_data_type: &DataType,
    ) -> Self {
        let mut gap = Self::new(gap);
        gap.prepare(order_data_type, gap_data_type).unwrap();
        gap
    }

    fn for_calc(&self) -> SessionFrameGapRef<'_> {
        SessionFrameGapRef {
            add_expr: self.add_expr.as_ref().unwrap().as_ref(),

View on GitHub (pinned to 6469eb736d)