risingwavelabs/risingwave · error

time parameter cannot be negative, got

Error message

time parameter cannot be negative, got {}

What it means

`expr_impl_to_u64_fn` converts a constant expression argument of `internal_get_channel_delta_stats` to u64. Int64 arguments are rejected if negative because a time parameter (at_time / time offset) cannot be negative.

Solutions

  1. Pass non-negative int64 values for both time arguments.
  2. If a relative offset, use the absolute difference or clamp negatives to 0.
  3. Wrap the argument expression so constant folding yields a non-negative value.
  4. Check unit semantics (seconds vs millis) which may have led to the negative value.

Example fix

-- before
SELECT * FROM internal_get_channel_delta_stats(-60, 0);
-- after
SELECT * FROM internal_get_channel_delta_stats(60, 0);
Defensive patterns

Strategy: validation

Validate before calling

-- Guard in SQL before calling
-- Ensure args are >= 0: use GREATEST(0, x) or check in client code

Type guard

fn as_non_neg_i64(v: i64) -> Option<u64> {
    if v < 0 { None } else { Some(v as u64) }
}

Try / catch

match expr_impl_to_u64_fn(expr) {
    Ok(v) => /* use v */,
    Err(e) => eprintln!("time parameter rejected: {e:#}"),
}

Prevention

When it happens

Trigger: `build_plan` for `internal_get_channel_delta_stats(at_time, time_offset)` folds an argument to a constant Int64 whose value is < 0, e.g. `internal_get_channel_delta_stats(-100, 200)`.

Common situations: Passing negative relative offsets by mistake, or computing offsets with expressions that evaluate to negative values (clock skew calculations).

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


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

Appendix: source

Thrown at src/frontend/src/optimizer/rule/table_function_to_internal_get_channel_delta_stats.rs:44

/// Helper function to extract a constant u64 value from an `ExprImpl`.
/// Returns `Ok(Some(value))` if the expression can be folded to a constant u64,
/// `Ok(None)` if the expression is null, or an error if folding fails.
/// Negative values are rejected as they are not valid for time parameters.
fn expr_impl_to_u64_fn(arg: &crate::expr::ExprImpl) -> anyhow::Result<Option<u64>> {
    match arg
        .clone()
        .cast_implicit(&DataType::Int64)?
        .try_fold_const()
    {
        Some(Ok(value)) => {
            let Some(scalar) = value else {
                return Ok(None);
            };
            match scalar {
                ScalarImpl::Int64(value) => {
                    if value < 0 {
                        Err(anyhow::anyhow!(
                            "time parameter cannot be negative, got {}",
                            value
                        ))
                    } else {
                        Ok(Some(value as u64))
                    }
                }
                _ => Err(anyhow::anyhow!("expected int64, got {:?}", scalar)),
            }
        }
        Some(Err(err)) => Err(anyhow!(err).context("failed to fold constant")),
        None => Err(anyhow::anyhow!("expression must be a constant value")),
    }
}

/// Transform the `internal_get_channel_delta_stats()` table function
/// into a plan graph which will return channel statistics from the dashboard API.
/// It will return channel stats with `upstream_fragment_id` and `downstream_fragment_id` as primary key.

View on GitHub (pinned to 6469eb736d)