risingwavelabs/risingwave · error

expression must be a constant value

Error message

expression must be a constant value

What it means

`expr_impl_to_u64_fn` requires each argument's constant-folded value to exist. When the fold yields `None` (expression is not constant), the function errors with `expression must be a constant value` because time parameters must be known at plan time.

Solutions

  1. Inline literal int64 constants for both arguments.
  2. Precompute the value in the client and pass it as a literal.
  3. Remove column references or subqueries from the arguments.
  4. Use a supported API (dashboard service) if runtime-parameterized stats are needed.

Example fix

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

Strategy: validation

Validate before calling

-- Arguments must be literals
SELECT * FROM internal_get_channel_delta_stats(3600, 0);

Try / catch

match expr_impl_to_u64_fn(expr) {
    Ok(v) => /* proceed */,
    Err(e) => eprintln!("arguments must be constants: {e:#}"),
}

Prevention

When it happens

Trigger: Calling `internal_get_channel_delta_stats` with arguments that depend on columns, parameters, or non-constant expressions, e.g. `internal_get_channel_delta_stats(some_col, 0)`.

Common situations: Attempting to parameterize the dashboard stats function with runtime values, or using session variables/non-deterministic expressions as arguments.

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/0a443b1605e153db. Report an issue: GitHub.

Appendix: source

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

            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.
pub struct TableFunctionToInternalGetChannelDeltaStatsRule {}
impl FallibleRule<Logical> for TableFunctionToInternalGetChannelDeltaStatsRule {
    fn apply(&self, plan: PlanRef) -> ApplyResult<PlanRef> {
        let logical_table_function: &LogicalTableFunction = plan.as_logical_table_function()?;
        if logical_table_function.table_function().function_type
            != TableFunctionType::InternalGetChannelDeltaStats
        {
            return ApplyResult::NotApplicable;
        }
        let plan = Self::build_plan(plan.ctx(), logical_table_function.table_function())?;
        ApplyResult::Ok(plan)
    }

View on GitHub (pinned to 6469eb736d)