risingwavelabs/risingwave · error

relative_error must be in the range (0, 1), got {}

Error message

relative_error must be in the range (0, 1), got {}

What it means

`approx_percentile` takes the relative error as a constant DIRECT argument of the aggregate call. The builder requires it to be strictly between 0 and 1 (exclusive) because it is used to compute ratio `base = (1+e)/(1-e)`, which is undefined or degenerate outside that range.

Source

Thrown at src/expr/impl/src/aggregate/approx_percentile.rs:43

use risingwave_expr::aggregate::{AggCall, AggStateDyn, AggregateFunction, AggregateState};
use risingwave_expr::{Result, build_aggregate};

/// TODO(kwannoel): for single phase agg, we can actually support `UDDSketch`.
/// For two phase agg, we still use `DDSketch`.
/// Then we also need to store the `relative_error` of the sketch, so we can report it
/// in an internal table, if it changes.
#[build_aggregate("approx_percentile(float8) -> float8", state = "bytea")]
fn build(agg: &AggCall) -> Result<Box<dyn AggregateFunction>> {
    let quantile = agg.direct_args[0]
        .literal()
        .map(|x| (*x.as_float64()).into())
        .unwrap();
    let relative_error: f64 = agg.direct_args[1]
        .literal()
        .map(|x| (*x.as_float64()).into())
        .unwrap();
    if relative_error <= 0.0 || relative_error >= 1.0 {
        bail!(
            "relative_error must be in the range (0, 1), got {}",
            relative_error
        )
    }
    let base = (1.0 + relative_error) / (1.0 - relative_error);
    Ok(Box::new(ApproxPercentile { quantile, base }))
}

pub struct ApproxPercentile {
    quantile: f64,
    base: f64,
}

type BucketCount = u64;
type BucketId = i32;
type Count = u64;

#[derive(Debug, Default)]

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Pass a relative error strictly between 0 and 1, e.g. 0.01 for ~1% error.
  2. Check argument order: quantile first, relative error second, both as literals.
  3. Remember the error is a fraction, not a percentage: use 0.05 not 5.

Example fix

// before
SELECT approx_percentile(latency, 0.95, 1.0) FROM t;
// after
SELECT approx_percentile(latency, 0.95, 0.01) FROM t;
Defensive patterns

Strategy: validation

Validate before calling

-- verify the error argument before running the query
-- in application code (JS example):
if (!(relErr > 0 && relErr < 1)) throw new Error('relative_error must be in (0,1)');

Try / catch

match approx_percentile_build(...) {
    Err(e) if e.to_string().contains("relative_error") => {
        // fall back to a default error like 0.01
    }
    other => other?,
}

Prevention

When it happens

Trigger: `approx_percentile(x, q, e)` called with e <= 0.0 or e >= 1.0, e.g. `approx_percentile(latency, 0.95, 1.0)` or `approx_percentile(latency, 0.95, 0)`, at materialized-view/aggregate build time.

Common situations: Confusing relative error with percentile (passing 0.95 as error); passing 0 expecting 'exact'; unit confusion (passing 100 for percent instead of 0.01-0.99).

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/59025ae58d5ad9c8. Report an issue: GitHub.