risingwavelabs/risingwave · error
frame bound offset should be non-negative, but
Error message
frame bound offset should be non-negative, but {} is given What it means
RANGE frame bound offsets must be non-negative. validate_non_negative checks the offset scalar (int, float, decimal) via IsNegative and rejects negative values, since a negative offset would invert frame semantics.
Solutions
- Use a non-negative offset and express direction with PRECEDING/FOLLOWING keywords, e.g. `RANGE BETWEEN 1 PRECEDING AND 5 PRECEDING` instead of negative numbers.
- Validate offset literals in the frontend before building frame bounds.
- If the offset is computed, clamp it to >= 0 at plan time.
Example fix
-- before SELECT sum(x) OVER (ORDER BY ts RANGE BETWEEN -1 PRECEDING AND 5 PRECEDING) FROM t; -- after SELECT sum(x) OVER (ORDER BY ts RANGE BETWEEN 1 PRECEDING AND 5 PRECEDING) FROM t;
Defensive patterns
Strategy: validation
Validate before calling
fn offset_non_negative(v: i64) -> bool { v >= 0 } Type guard
fn is_valid_offset(d: &Datum) -> bool {
match d {
Some(ScalarImpl::Int64(v)) => *v >= 0,
Some(ScalarImpl::Interval(i)) => i.is_never_negative(),
_ => false,
}
} Prevention
- Express direction with PRECEDING/FOLLOWING, never negative offsets.
- Validate offset literals in the SQL binder.
- Clamp computed offsets to >= 0 before frame construction.
When it happens
Trigger: Creating a RangeFrameBounds with an offset like -5 for `RANGE BETWEEN -5 PRECEDING ...` or a negative interval offset, then calling validate (via from_protobuf/construction).
Common situations: User SQL like `RANGE BETWEEN 5 PRECEDING AND -1 PRECEDING`, or planner emitting a negative offset after constant folding.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- for frame bound offset of type `interval`, each field…
- for frame order column of type `timestamptz`, offset should…
- frame end cannot be UNBOUNDED PRECEDING
- frame start cannot be UNBOUNDED FOLLOWING
- frame starting from current row cannot have preceding rows
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/04bc9e4262666ccc.
Report an issue: GitHub.
Appendix: source
Thrown at src/expr/core/src/window_function/range.rs:99
}
impl Display for RangeFrameBounds {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"RANGE BETWEEN {} AND {}",
self.start.for_display(),
self.end.for_display()
)?;
Ok(())
}
}
impl FrameBoundsImpl for RangeFrameBounds {
fn validate(&self) -> Result<()> {
fn validate_non_negative(val: impl IsNegative + Display) -> Result<()> {
if val.is_negative() {
bail!(
"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() {View on GitHub (pinned to 6469eb736d)