risingwavelabs/risingwave · error

failed to evaluate the input for normal arm

Error message

failed to evaluate the input for normal arm

What it means

In the constant-lookup CASE expression, when the input datum matches a WHEN constant, the corresponding `then` expression is evaluated for the row. If that evaluation fails, the `lookup!` macro bails with this generic message, masking the underlying expression error.

Source

Thrown at src/expr/impl/src/scalar/case.rs:194

    ($mode:ident, $this:expr, $input:expr) => {{
        if let Some(ref fallback) = $this.fallback {
            let Ok(res) = risingwave_expr::forward!($mode, fallback, eval_row($input)) else {
                bail!("failed to evaluate the input for fallback arm");
            };
            Ok::<Datum, risingwave_expr::ExprError>(res)
        } else {
            Ok::<Datum, risingwave_expr::ExprError>(None)
        }
    }};
}

macro_rules! lookup {
    ($mode:ident, $this:expr, $datum:expr, $input:expr) => {{
        match $datum.as_ref() {
            Some(datum) => {
                if let Some(expr) = $this.arms.get(datum) {
                    let Ok(res) = risingwave_expr::forward!($mode, expr, eval_row($input)) else {
                        bail!("failed to evaluate the input for normal arm");
                    };
                    Ok(res)
                } else {
                    eval_fallback_lookup!($mode, $this, $input)
                }
            }
            None => eval_fallback_lookup!($mode, $this, $input),
        }
    }};
}

macro_rules! eval_constant_lookup {
    ($mode:ident, $this:expr, $input:expr) => {{
        let input_len = $input.capacity();
        let mut builder = $this.return_type().create_array_builder(input_len);

        // Evaluate the input DataChunk at first
        let eval_result = risingwave_expr::forward!($mode, $this.operand, eval($input))?;

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Harden the THEN expressions: wrap risky casts/arithmetic in COALESCE or CASE guards.
  2. Identify the offending rows by evaluating each then expression independently.
  3. Add explicit type handling so the then expression is total over the input domain.

Example fix

// before
CASE status WHEN 1 THEN (raw::int * 100)::text ELSE 'other' END
// after
CASE status WHEN 1 THEN COALESCE((raw::int * 100)::text, 'invalid') ELSE 'other' END
Defensive patterns

Strategy: try-catch

Validate before calling

-- harden THEN arms before execution:
-- THEN COALESCE((x::int)::text, 'default')

Try / catch

match result {
    Err(e) if e.to_string().contains("failed to evaluate the input for normal arm") => {
        // find the matched arm and its failing row input
    }
    other => other?,
}

Prevention

When it happens

Trigger: Evaluating a CASE with constant WHEN keys where the matched THEN arm's expression errors on a specific row (overflow, failed cast, function domain error inside the then expression).

Common situations: THEN arms containing casts or arithmetic that fail on particular rows; data arriving in a materialized view refresh that violates assumptions of the then expression.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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