risingwavelabs/risingwave · error

for session gap of type `interval`, each field should be…

Error message

for session gap of type `interval`, each field should be non-negative, but {} is given

What it means

For interval-typed session gaps, a simple sign check is insufficient because an Interval has months/days/microseconds fields. Validation uses `is_never_negative()`, requiring every field of the interval to be non-negative (e.g. '1 month -1 day' is rejected even if the total duration is positive).

Solutions

  1. Rewrite the gap so all interval fields are non-negative (e.g. INTERVAL '1 month 1 day')
  2. Normalize the interval before passing it (split/abs each field)
  3. Clamp negative fields to zero in the expression producing the gap

Example fix

// before
SESSION(INTERVAL '1 month -1 day')
// after
SESSION(INTERVAL '1 month 1 day')
Defensive patterns

Strategy: validation

Validate before calling

fn interval_never_negative(i: Interval) -> bool { i.is_never_negative() }

Type guard

fn safe_interval_gap(i: Interval) -> bool { i.months() >= 0 && i.days() >= 0 && i.useconds() >= 0 }

Try / catch

if !gap.is_never_negative() {
    return Err(anyhow!("each interval field of the session gap must be non-negative"));
}

Prevention

When it happens

Trigger: Session window with an interval gap where any component field is negative, e.g. `INTERVAL '1 month -1 day'` or `INTERVAL '-5 seconds'`, detected in `validate` (via `is_canonical`).

Common situations: Arithmetic on intervals producing mixed-sign components; users assuming total-duration semantics instead of per-field semantics.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        // TODO(rc): maybe can merge with `RangeFrameBounds::validate`

        fn validate_non_negative(val: impl IsNegative + Display) -> Result<()> {
            if val.is_negative() {
                bail!("session gap should be non-negative, but {} is given", val);
            }
            Ok(())
        }

        match self.gap.as_scalar_ref_impl() {
            ScalarRefImpl::Int16(val) => validate_non_negative(val)?,
            ScalarRefImpl::Int32(val) => validate_non_negative(val)?,
            ScalarRefImpl::Int64(val) => validate_non_negative(val)?,
            ScalarRefImpl::Float32(val) => validate_non_negative(val)?,
            ScalarRefImpl::Float64(val) => validate_non_negative(val)?,
            ScalarRefImpl::Decimal(val) => validate_non_negative(val)?,
            ScalarRefImpl::Interval(val) => {
                if !val.is_never_negative() {
                    bail!(
                        "for session gap of type `interval`, each field should be non-negative, but {} is given",
                        val
                    );
                }
                if matches!(self.order_data_type, DataType::Timestamptz) {
                    // for `timestamptz`, we only support gap without `month` and `day` fields
                    if val.months() != 0 || val.days() != 0 {
                        bail!(
                            "for session order column of type `timestamptz`, gap should not have non-zero `month` and `day`",
                        );
                    }
                }
            }
            _ => unreachable!(
                "other order column data types are not supported and should be banned in frontend"
            ),
        }
        Ok(())

View on GitHub (pinned to 6469eb736d)