{"record":{"id":"2c162baf579fffcb","repo":"risingwavelabs/risingwave","slug":"type-mismatched-between-when-clause-and-condition","errorCode":null,"errorMessage":"Type mismatched between when clause and condition","messagePattern":"Type mismatched between when clause and condition","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/scalar/case.rs","lineNumber":349,"sourceCode":"            .boxed());\n        }\n        None => None,\n    };\n    Ok(ConstantLookupExpression::new(return_type, sync_arms, fallback, operand).boxed())\n}\n\n#[build_function(\"case(...) -> any\", type_infer = \"unreachable\")]\nfn build_case_expr(\n    return_type: DataType,\n    children: Vec<BoxedExpression>,\n) -> Result<BoxedExpression> {\n    // children: (when, then)+, (else_clause)?\n    let len = children.len();\n    let mut when_clauses = Vec::with_capacity(len / 2);\n    let mut iter = children.into_iter().array_chunks();\n    for [when, then] in iter.by_ref() {\n        if when.return_type() != DataType::Boolean {\n            bail!(\"Type mismatched between when clause and condition\");\n        }\n        if then.return_type() != return_type {\n            bail!(\"Type mismatched between then clause and case\");\n        }\n        when_clauses.push(WhenClause { when, then });\n    }\n    let else_clause = if let Some(else_clause) = iter.into_remainder().next() {\n        if else_clause.return_type() != return_type {\n            bail!(\"Type mismatched between else and case.\");\n        }\n        Some(else_clause)\n    } else {\n        None\n    };\n\n    let sync_when_clauses = match try_convert_all(\n        when_clauses,\n        |WhenClause { when, then }| match (when, then) {","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/scalar/case.rs#L331-L367","documentation":"In `build_case_expr`, every WHEN condition expression must return BOOLEAN, since CASE conditions are logically evaluated as predicates. A non-boolean WHEN type means the query plan is malformed, so the builder rejects it.","triggerScenarios":"`build_case_expr` receiving a (when, then) pair whose `when` expression's return type is not `DataType::Boolean` — e.g. an integer used directly as a condition without an explicit comparison, or a planner that failed to insert a boolean cast.","commonSituations":"Porting SQL that relies on non-standard truthy semantics (e.g. `CASE x WHEN 1 THEN ...` translated incorrectly to searched CASE); frontend type inference bugs; schema changes turning a boolean column into int.","solutions":["Wrap the condition in an explicit comparison: `CASE WHEN col = 1 THEN ...` instead of `CASE WHEN col THEN ...`.","Add an explicit cast/comparison so the condition is boolean.","Verify the frontend type coercion rules for searched CASE conditions."],"exampleFix":"// before\nCASE WHEN status THEN 'active' ELSE 'inactive' END  -- status is int\n// after\nCASE WHEN status = 1 THEN 'active' ELSE 'inactive' END","handlingStrategy":"validation","validationCode":"-- ensure condition is boolean before CASE\nCASE WHEN status = 1 THEN ... -- not CASE WHEN status THEN ...\n-- app-side guard:\nif (whenExpr.returnType !== 'boolean') wrapInComparison(whenExpr);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never rely on truthy integer semantics in searched CASE.","Always write conditions as explicit boolean comparisons.","Check for schema drift turning boolean columns into other types."],"tags":["rust","type-mismatch","case-expression","sql"],"backgroundTag":"type-mismatch","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}