risingwavelabs/risingwave · error

failed to evaluate the input for fallback arm

Error message

failed to evaluate the input for fallback arm

What it means

In the constant-lookup CASE implementation, when a lookup misses all arms the fallback (ELSE) expression is evaluated row-by-row. If that evaluation returns an Err, the macro cannot distinguish expression errors from control flow, so it rethrows this generic wrapper error, discarding the underlying cause.

Source

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

            return_type,
            arms,
            fallback,
            operand,
        }
    }
}

impl<E: ExpressionInfo> ExpressionInfo for ConstantLookupExpression<E> {
    fn return_type(&self) -> DataType {
        self.return_type.clone()
    }
}

macro_rules! eval_fallback_lookup {
    ($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 {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check the ELSE expression for operations that can fail per-row (casts, division, function domains) and make them total (COALESCE, safe casts).
  2. Test the else expression standalone on the offending input values.
  3. If you need the real root cause, run the same expression without the constant-lookup optimization path or check debug logs.

Example fix

// before
CASE key WHEN 1 THEN 'a' WHEN 2 THEN 'b' ELSE (val::int / divisor)::text END
// after
CASE key WHEN 1 THEN 'a' WHEN 2 THEN 'b' ELSE COALESCE((NULLIF(divisor,0) IS NULL, ...)::text, 'n/a') END
Defensive patterns

Strategy: try-catch

Validate before calling

-- make the else arm total before execution
-- ensure all casts in ELSE use COALESCE/NULLIF guards

Try / catch

match result {
    Err(e) if e.to_string().contains("failed to evaluate the input for fallback arm") => {
        // inspect ELSE expression inputs for the offending row
    }
    other => other?,
}

Prevention

When it happens

Trigger: Evaluating a CASE expression built with `build_constant_lookup_expr` where the input datum matches no WHEN constant and the ELSE clause's evaluation fails on that row (e.g. cast overflow, division by zero, domain violation inside the else arm).

Common situations: ELSE clause performing arithmetic on NULL-typed or out-of-domain data; casts inside the else arm failing for particular rows in a materialized view refresh or query.

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/1c75b4b6f258fd71. Report an issue: GitHub.