risingwavelabs/risingwave · error

for frame bound offset of type `interval`, each field…

Error message

for frame bound offset of type `interval`, each field should be non-negative, but {} is given

What it means

For RANGE frames whose offset is an Interval, every field of the interval (months, days, microseconds) must be non-negative. validate in RangeFrameBounds rejects intervals where any component is negative, because mixed-sign intervals make frame comparisons ambiguous.

Solutions

  1. Use positive interval literals and express direction via PRECEDING/FOLLOWING, e.g. `INTERVAL '1 day' PRECEDING`.
  2. Normalize computed intervals so all fields are non-negative before building the frame.
  3. Reject or rewrite such frames in the frontend binder/planner.

Example fix

-- before
SELECT sum(x) OVER (ORDER BY ts RANGE BETWEEN INTERVAL '-1 day' PRECEDING AND CURRENT ROW) FROM t;
-- after
SELECT sum(x) OVER (ORDER BY ts RANGE BETWEEN INTERVAL '1 day' PRECEDING AND CURRENT ROW) FROM t;
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Prevention

When it happens

Trigger: RANGE frame with an Interval offset that is not never-negative, e.g. `RANGE BETWEEN INTERVAL '-1 day' PRECEDING ...` or `INTERVAL '1 month -1 day'`, when validate runs on the constructed bounds.

Common situations: SQL with signed interval literals like `'-1 day'`, or computed interval offsets that can go negative depending on input.

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/5808972cf658c23c. Report an issue: GitHub.

Appendix: source

Thrown at src/expr/core/src/window_function/range.rs:118

                    "frame bound offset should be non-negative, but {} is given",
                    val
                );
            }
            Ok(())
        }

        FrameBound::validate_bounds(&self.start, &self.end, |offset| {
            match offset.as_scalar_ref_impl() {
                // TODO(rc): use decl macro?
                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 frame bound offset 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 offset without `month` and `day` fields
                        if val.months() != 0 || val.days() != 0 {
                            bail!(
                                "for frame order column of type `timestamptz`, offset 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)