vitessio/vitess · error
unsupported type %T
Error message
unsupported type %T
What it means
evalToFloat converts any eval engine value to a float. When handed a value whose concrete type is not one of the handled numeric/enum/set/string-ish types, it panics with "unsupported type %T". This indicates the eval engine received an AST/expr value type that numeric coercion was never designed to handle, i.e. an internal invariant violation rather than user data error.
Source
Thrown at go/vt/vtgate/evalengine/eval_numeric.go:229
}
return &evalFloat{f: 0.0}, true
case json.TypeNumber:
f, ok := e.Float64()
return &evalFloat{f: f}, ok
case json.TypeString:
val, err := fastparse.ParseFloat64(e.Raw())
return &evalFloat{f: val}, err == nil
default:
return &evalFloat{f: 0}, true
}
case *evalTemporal:
return &evalFloat{f: e.toFloat()}, true
case *evalEnum:
return &evalFloat{f: float64(enumNumeric(e.value))}, e.value != -1
case *evalSet:
return &evalFloat{f: float64(e.set)}, true
default:
panic(fmt.Sprintf("unsupported type %T", e))
}
}
func evalToDecimal(e eval, m, d int32) *evalDecimal {
switch e := e.(type) {
case evalNumeric:
return e.toDecimal(m, d)
case *evalBytes:
if e.isHexLiteral() {
hex, ok := e.toNumericHex()
if !ok {
// overflow
return newEvalDecimal(decimal.Zero, m, d)
}
return hex.toDecimal(m, d)
}
if e.isBitLiteral() {
bit, ok := e.toNumericBit()View on GitHub (pinned to 01a25a7d17)
Solutions
- Identify the type printed in the panic (%T) and add a case for it in evalToFloat in go/vt/vtgate/evalengine/eval_numeric.go
- If the type should never reach float coercion, fix the caller (evalCoerce/evalCompare) to route or reject that type earlier
- Check the vitess version; upgrade to a release where the new type is supported in numeric coercion
Example fix
// before
default:
panic(fmt.Sprintf("unsupported type %T", e))
// after
case *evalMyNewType:
return &evalFloat{f: e.toFloat()}, true
default:
panic(fmt.Sprintf("unsupported type %T", e)) Defensive patterns
Strategy: type-guard
Validate before calling
// before relying on float coercion
if _, ok := v.(evalNumeric); !ok {
switch v.(type) {
case *evalEnum, *evalSet:
default:
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "cannot coerce %T to float", v)
}
} Type guard
func isFloatCoercible(e eval) bool {
switch e.(type) {
case evalNumeric, *evalEnum, *evalSet:
return true
default:
return false
}
} Try / catch
// Go panics are not errors; recover at query-evaluation boundary
func safeEvalToFloat(e eval) (f *evalFloat, err error) {
defer func() {
if r := recover(); r != nil {
err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "evalToFloat: %v", r)
}
}()
fl, _ := evalToFloat(e)
return fl, nil
} Prevention
- When adding a new eval type, grep for 'unsupported type' in eval_numeric.go and update all conversion switches
- Run the evalengine unit tests that exercise compare/coerce for every type
- Route non-scalar types away from numeric coercion during expression type analysis
When it happens
Trigger: Calling evalToFloat (directly or via evalCoerce, valueToEvalCast, evalCompare, compareAllFloat) with an eval implementation not covered by the type switch, e.g. a newly added eval type (like a new temporal or JSON variant) that was not added to the switch in eval_numeric.go.
Common situations: Developers extending the eval engine with a new eval type but forgetting to update evalToFloat; plugin or comparison code feeding an unexpected expression result into float comparison.
Related errors
- unsupported type: %T
- malformed hex literal from parser
- bad unsigned integer type
- bad type aggregation for signed/unsigned types
- unreachable
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/76ce046e4bc52fe6.
Report an issue: GitHub.