{"record":{"id":"f2c6f133cd29a048","repo":"databendlabs/databend","slug":"a-partially-folded-top-level-cast-must-remain-a-ca","errorCode":null,"errorMessage":"a partially folded top-level cast must remain a cast","messagePattern":"a partially folded top-level cast must remain a cast","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/query/sql/src/planner/semantic/type_check/scalar_function.rs","lineNumber":686,"sourceCode":"\n        if !expr.is_deterministic(&BUILTIN_FUNCTIONS) {\n            self.adapter.set_result_cache_uncacheable();\n        }\n\n        let expr = match self.try_fold_constant(expr) {\n            Ok(constant) => return Ok(constant),\n            Err(expr) => expr,\n        };\n\n        if is_top_level_cast {\n            let expr::Expr::Cast(expr::Cast {\n                span,\n                is_try,\n                dest_type,\n                ..\n            }) = expr\n            else {\n                unreachable!(\"a partially folded top-level cast must remain a cast\");\n            };\n            assert_eq!(folded_args.len(), 1);\n            return Ok(Box::new((\n                CastExpr {\n                    span,\n                    is_try,\n                    argument: Box::new(folded_args.pop().unwrap()),\n                    target_type: Box::new(dest_type.clone()),\n                }\n                .into(),\n                dest_type,\n            )));\n        }\n\n        // reorder\n        if func_name == \"eq\"\n            && folded_args.len() == 2\n            && matches!(folded_args[0], ScalarExpr::ConstantExpr(_))","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/sql/src/planner/semantic/type_check/scalar_function.rs#L668-L704","documentation":"A defensive assertion in Databend's scalar function resolver: after constant folding, the code expects that any expression still needing a cast remains a top-level CastExpr. If the folded expression has a different shape, the match arm fails and panics with \"a partially folded top-level cast must remain a cast\". It indicates the constant folder produced an expression shape the resolver did not anticipate.","triggerScenarios":"resolve_scalar_function_call folding arguments of casts/functions (reached via resolve_in_list, merge_or_level, fold_or_levels, resolve_array/map/tuple) where the folding of a CAST expression rewrites the top-level node into something other than CastExpr — e.g. nested casts of constant expressions under unusual type combinations.","commonSituations":"Complex constant expressions mixing casts, arrays, tuples, and OR-lists (e.g. WHERE x IN (...CAST...)) in queries run against a version where the folder was recently changed; upgraded Databend binaries where a folding optimization regressed.","solutions":["Simplify the query: hoist constant casts out of IN lists / OR chains into literals or separate expressions","Apply casts explicitly to columns rather than to deeply nested constant expressions","Reduce the query to a minimal reproducer and test against the latest Databend release — this is a folder regression likely already fixed upstream","Report the bug with the failing SQL if it reproduces on the latest version"],"exampleFix":"// before\nSELECT * FROM t WHERE a IN (CAST('1' AS INT) + 1, 3);\n// after: precompute the constant\nSELECT * FROM t WHERE a IN (2, 3);","handlingStrategy":"fallback","validationCode":"-- avoid deep constant-folded casts inside IN/OR predicates\n-- precompute: SELECT CAST('1' AS INT) + 1; and inline the literal","typeGuard":null,"tryCatchPattern":"match res {\n    Err(e) if e.to_string().contains(\"partially folded top-level cast\") => {\n        // rewrite query with precomputed constants and retry\n    }\n    r => r,\n}","preventionTips":["Precompute constant expressions in application code or via literals instead of nested casts inside predicates","Keep Databend up to date — folding regressions are fixed quickly upstream","Simplify OR/IN predicates with explicit literal values"],"tags":["internal-invariant","constant-folding","type-cast","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}