{"record":{"id":"6ec4a11eef07926f","repo":"vitessio/vitess","slug":"unsupported","errorCode":null,"errorMessage":"unsupported","messagePattern":"unsupported","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/eval_numeric.go","lineNumber":169,"sourceCode":"\t\t\tf, _ := fastparse.ParseFloat64(e.Raw())\n\t\t\treturn &evalFloat{f: f}\n\t\tdefault:\n\t\t\treturn &evalFloat{f: 0}\n\t\t}\n\tcase *evalTemporal:\n\t\tif preciseDatetime {\n\t\t\tif e.prec == 0 {\n\t\t\t\treturn newEvalInt64(e.toInt64())\n\t\t\t}\n\t\t\treturn newEvalDecimalWithPrec(e.toDecimal(), int32(e.prec))\n\t\t}\n\t\treturn &evalFloat{f: e.toFloat()}\n\tcase *evalEnum:\n\t\treturn &evalFloat{f: float64(enumNumeric(e.value))}\n\tcase *evalSet:\n\t\treturn &evalFloat{f: float64(e.set)}\n\tdefault:\n\t\tpanic(\"unsupported\")\n\t}\n}\n\nfunc evalToFloat(e eval) (*evalFloat, bool) {\n\tswitch e := e.(type) {\n\tcase *evalFloat:\n\t\treturn e, true\n\tcase evalNumeric:\n\t\treturn e.toFloat()\n\tcase *evalBytes:\n\t\tif e.isHexLiteral() {\n\t\t\thex, ok := e.toNumericHex()\n\t\t\tif !ok {\n\t\t\t\t// overflow\n\t\t\t\treturn newEvalFloat(0), false\n\t\t\t}\n\t\t\tf, ok := hex.toFloat()\n\t\t\tif !ok {","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/eval_numeric.go#L151-L187","documentation":"evalToNumeric converts any eval value to a numeric one for arithmetic and comparisons, with a default case that panics('unsupported') for eval types that have no numeric representation (e.g. JSON, tuples, geometry). The dispatch layer must filter such types before calling. Hitting it means an unsupported eval type leaked into numeric arithmetic — normally guarded by earlier type checks.","triggerScenarios":"Arithmetic operators (subtractNumericWithError, divideNumericWithError, modNumericWithError), evalCompare, or eval dispatch calling evalToNumeric on a type like *evalJSON or *evalTuple that wasn't rejected earlier — e.g. `json_col + 1` on a code path that skipped the type-error check, or a new eval type missing from the switch.","commonSituations":"Queries applying arithmetic to non-numeric values (JSON columns, comparisons after schema/type changes) that slip past the engine's type validation; engine development adding new eval types.","solutions":["Ensure the query/operator validates operand types before arithmetic (e.g. JSON operands should be extracted with JSON_EXTRACT/CAST first)","Wrap the offending operand with an explicit CAST to a numeric type in the SQL query","If adding a new eval type, add a case in evalToNumeric (eval_numeric.go:~140) defining its numeric conversion","Report the exact query to Vitess with a stack trace if it panics on stock code — it likely indicates a missing type check"],"exampleFix":"// before\nSELECT json_col + 1 FROM t;\n// after\nSELECT CAST(json_col AS DECIMAL) + 1 FROM t; -- or use JSON_EXTRACT(json_col, '$')","handlingStrategy":"type-guard","validationCode":"// SQL: cast non-numeric operands before arithmetic\nSELECT CAST(json_col AS UNSIGNED) + 1 FROM t;","typeGuard":"// Go: reject non-numeric evals before evalToNumeric\nfunc isArithmeticOperand(e eval) bool {\n\tswitch e.(type) {\n\tcase *evalJSON, *evalTuple:\n\t\treturn false\n\t}\n\treturn true\n}","tryCatchPattern":"func safeToNumeric(e eval) (n eval, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = vterrors.Errorf(vtrpcpb.Code_INTERNAL, \"numeric conversion failed: %v\", r)\n\t\t}\n\t}()\n\treturn evalToNumeric(e), nil\n}","preventionTips":["Never apply arithmetic operators to JSON/tuple/geometry expressions; extract and CAST first","Validate operand types at typechecking time so evalToNumeric only sees numeric-capable evals","When adding eval types, update evalToNumeric's switch in the same change and add pair tests with all arithmetic ops"],"tags":["go","panic","evalengine","arithmetic","type-conversion"],"backgroundTag":"unsupported-type-arithmetic-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}