databendlabs/databend · error

unexpected value type for grouping function

Error message

unexpected value type for grouping function: {:?}

What it means

The `grouping` scalar function factory in src/query/functions/src/scalars/other.rs registers an evaluator that expects the GROUPING argument to arrive as a column value it can iterate; any other `Value` variant (e.g. a scalar Value instead of Value::Column, or another column type) triggers `unreachable!("unexpected value type for grouping function: {:?}")`. It is an internal invariant that the type checker/binder normalized arguments before scalar evaluation.

Solutions

  1. Ensure the GROUPING function is rewritten during type checking before scalar evaluation runs (see error 57's companion unreachable).
  2. Inspect the logged value shape in the panic message and add a matching match arm (e.g. Value::Scalar) with correct semantics if that shape is legitimate.
  3. If invoking the factory directly, construct arguments as Value::Column(Column::Number(NumberColumn::UInt32/...)) as the evaluator expects.
  4. Convert the unreachable!() into a returned FunctionError so malformed input fails gracefully.

Example fix

// before
v => unreachable!("unexpected value type for grouping function: {:?}", v),
// after
Value::Scalar(s) => {
    let out = compute_grouping(&params, s_as_u32(&s));
    Value::Column(Column::Number(NumberColumn::UInt32(vec![out])))
}
v => Err(ErrorCode::BadArguments(format!(
    "unexpected value type for grouping function: {:?}", v))),
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard the argument shape before invoking the grouping evaluator:
fn is_grouping_column(v: &Value) -> bool {
    matches!(v, Value::Column(Column::Number(_)))
}

Type guard

fn as_grouping_column(v: &Value) -> Option<&Column> {
    match v {
        Value::Column(c @ Column::Number(_)) => Some(c),
        _ => None,
    }
}

Try / catch

// Panics are not catchable in Rust by default; isolate evaluation:
let result = std::panic::catch_unwind(|| grouping_eval(&args));
match result {
    Ok(v) => v,
    Err(_) => return Err(ErrorCode::BadArguments("grouping arg must be a number column")),
}

Prevention

When it happens

Trigger: Executing a GROUPING(...) call whose argument reaches scalar evaluation as a Value variant other than Value::Column backed by NumberColumn (e.g. a constant-folded scalar, nullable/large-list column, or a Value::Scalar from const evaluation) instead of being rewritten by the type checker.

Common situations: Query plans where GROUPING's argument was constant-folded before evaluation; new column encodings introduced after this code was written; calling the registered function factory directly from custom tooling or tests with hand-built arguments.

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

Appendix: source

Thrown at src/query/functions/src/scalars/other.rs:413

            signature: FunctionSignature {
                name: "grouping".to_string(),
                args_type: vec![DataType::Number(NumberDataType::UInt32)],
                return_type: DataType::Number(NumberDataType::UInt32),
            },
            eval: FunctionEval::Scalar {
                calc_domain: Box::new(FunctionDomain::Full),
                eval: scalar_evaluator(move |args, _| match &args[0] {
                    Value::Scalar(Scalar::Number(NumberScalar::UInt32(v))) => Value::Scalar(
                        Scalar::Number(NumberScalar::UInt32(compute_grouping(&params, *v))),
                    ),
                    Value::Column(Column::Number(NumberColumn::UInt32(col))) => {
                        let output = col
                            .iter()
                            .map(|v| compute_grouping(&params, *v))
                            .collect::<Vec<_>>();
                        Value::Column(Column::Number(NumberColumn::UInt32(output.into())))
                    }
                    v => unreachable!("unexpected value type for grouping function: {:?}", v),
                }),
                derive_stat: None,
            },
        }))
    }));
    registry.register_function_factory("grouping", grouping);

    // dummy grouping
    // used in type_check before AggregateRewriter
    let dummy_grouping = FunctionFactory::Closure(Box::new(|_, arg_type: &[DataType]| {
        Some(Arc::new(Function {
            signature: FunctionSignature {
                name: "grouping".to_string(),
                args_type: vec![DataType::Generic(0); arg_type.len()],
                return_type: DataType::Number(NumberDataType::UInt32),
            },
            eval: FunctionEval::Scalar {
                calc_domain: Box::new(FunctionDomain::Full),

View on GitHub (pinned to 288d84d76e)