risingwavelabs/risingwave · error

Type mismatched between else and case.

Error message

Type mismatched between else and case.

What it means

In `build_constant_lookup_expr`, the optional trailing ELSE clause must have the same return type as the CASE's declared return type. A mismatch would make the output column type inconsistent at runtime, so the builder rejects it during construction.

Source

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

    let mut children = children;

    let operand = children.remove(0);

    let mut arms = HashMap::new();

    // Build the `arms` with iterating over `when` & `then` clauses
    let mut iter = children.into_iter().array_chunks();
    for [when, then] in iter.by_ref() {
        let Ok(Some(s)) = when.eval_const() else {
            bail!("expect when expression to be const");
        };
        arms.insert(s, then);
    }

    let fallback = if let Some(else_clause) = iter.into_remainder().next() {
        if else_clause.return_type() != return_type {
            bail!("Type mismatched between else and case.");
        }
        Some(else_clause)
    } else {
        None
    };

    let BoxedExpression::Sync(operand) = operand else {
        return Ok(ConstantLookupExpression::new(return_type, arms, fallback, operand).boxed());
    };
    let arms: Vec<_> = arms.into_iter().collect();
    let sync_arms: HashMap<ScalarImpl, Arc<dyn SyncExpression>> = match try_convert_all(
        arms,
        |(key, expr)| match expr {
            BoxedExpression::Sync(expr) => Ok((key, expr)),
            expr @ BoxedExpression::Async(_) => Err((key, expr)),
        },
        |(key, expr)| (key, BoxedExpression::Sync(expr)),
    ) {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Add an explicit cast on the ELSE clause to match the CASE return type.
  2. Verify the type inference pass assigned a common return type across all THEN/ELSE arms.
  3. Check for schema drift in the columns referenced by the ELSE expression.

Example fix

// before
CASE key WHEN 1 THEN 'a' ELSE 42 END  -- else is int, case is varchar
// after
CASE key WHEN 1 THEN 'a' ELSE 42::varchar END
Defensive patterns

Strategy: validation

Validate before calling

-- assert else type matches case return type before build
-- app-side check:
if (elseExpr.returnType !== caseReturnType) addCast(elseExpr, caseReturnType);

Prevention

When it happens

Trigger: Building a constant-lookup CASE where the ELSE expression's DataType differs from the CASE return_type (e.g. ELSE returns INT when the CASE was typed as VARCHAR), typically when RETURN_TYPE coercion was skipped or types were declared incorrectly upstream.

Common situations: Hand-built expression trees; frontend type-inference bugs where implicit casts to the common type were not inserted; schema changes altering a column type used in ELSE.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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