databendlabs/databend · critical

a partially folded top-level cast must remain a cast

Error message

a partially folded top-level cast must remain a cast

What it means

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.

Solutions

  1. Simplify the query: hoist constant casts out of IN lists / OR chains into literals or separate expressions
  2. Apply casts explicitly to columns rather than to deeply nested constant expressions
  3. Reduce the query to a minimal reproducer and test against the latest Databend release — this is a folder regression likely already fixed upstream
  4. Report the bug with the failing SQL if it reproduces on the latest version

Example fix

// before
SELECT * FROM t WHERE a IN (CAST('1' AS INT) + 1, 3);
// after: precompute the constant
SELECT * FROM t WHERE a IN (2, 3);
Defensive patterns

Strategy: fallback

Validate before calling

-- avoid deep constant-folded casts inside IN/OR predicates
-- precompute: SELECT CAST('1' AS INT) + 1; and inline the literal

Try / catch

match res {
    Err(e) if e.to_string().contains("partially folded top-level cast") => {
        // rewrite query with precomputed constants and retry
    }
    r => r,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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 databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/f2c6f133cd29a048. Report an issue: GitHub.

Appendix: source

Thrown at src/query/sql/src/planner/semantic/type_check/scalar_function.rs:686

        if !expr.is_deterministic(&BUILTIN_FUNCTIONS) {
            self.adapter.set_result_cache_uncacheable();
        }

        let expr = match self.try_fold_constant(expr) {
            Ok(constant) => return Ok(constant),
            Err(expr) => expr,
        };

        if is_top_level_cast {
            let expr::Expr::Cast(expr::Cast {
                span,
                is_try,
                dest_type,
                ..
            }) = expr
            else {
                unreachable!("a partially folded top-level cast must remain a cast");
            };
            assert_eq!(folded_args.len(), 1);
            return Ok(Box::new((
                CastExpr {
                    span,
                    is_try,
                    argument: Box::new(folded_args.pop().unwrap()),
                    target_type: Box::new(dest_type.clone()),
                }
                .into(),
                dest_type,
            )));
        }

        // reorder
        if func_name == "eq"
            && folded_args.len() == 2
            && matches!(folded_args[0], ScalarExpr::ConstantExpr(_))

View on GitHub (pinned to 288d84d76e)