{"record":{"id":"0bdfb197b2cf3c61","repo":"vitessio/vitess","slug":"unexpected-argument-type","errorCode":null,"errorMessage":"unexpected argument type","messagePattern":"unexpected argument type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/fn_compare.go","lineNumber":256,"sourceCode":"\tif binary > 0 || text > 0 {\n\t\tif text > 0 {\n\t\t\treturn compareAllText\n\t\t}\n\t\tif binary > 0 {\n\t\t\treturn compareAllBinary\n\t\t}\n\t} else {\n\t\tif floats > 0 {\n\t\t\treturn compareAllFloat\n\t\t}\n\t\tif decimals > 0 {\n\t\t\treturn compareAllDecimal\n\t\t}\n\t\tif json > 0 {\n\t\t\treturn compareAllText\n\t\t}\n\t}\n\tpanic(\"unexpected argument type\")\n}\n\nfunc compareAllTemporal(f func(env *ExpressionEnv, arg eval, prec int) *evalTemporal) multiComparisonFunc {\n\treturn func(env *ExpressionEnv, args []eval, cmp, prec int) (eval, error) {\n\t\tvar x *evalTemporal\n\t\tfor _, arg := range args {\n\t\t\tconv := f(env, arg, prec)\n\t\t\tif x == nil {\n\t\t\t\tx = conv\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (cmp < 0) == (conv.compare(x) < 0) {\n\t\t\t\tx = conv\n\t\t\t}\n\t\t}\n\t\treturn x, nil\n\t}\n}","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/fn_compare.go#L238-L274","documentation":"getMultiComparisonFunc picks the comparison strategy (numeric, temporal, text, etc.) for multi-argument comparisons like LEAST/GREATEST/INTERVAL based on the type signature of the arguments. The panic fires when the accumulated type counters don't match any known combination, meaning the typechecker allowed an argument-type mix this function never anticipated.","triggerScenarios":"Evaluating LEAST/GREATEST/INTERVAL-style functions whose argument type combination (counts of numeric, temporal, json, text args) falls through all the if-branches of getMultiComparisonFunc — e.g., a mix of types the typechecker accepted but this dispatcher does not handle.","commonSituations":"Queries comparing exotic type mixes (e.g., temporal with JSON) through these functions; evalengine development where new type kinds were added without updating the dispatcher; tests building argument lists directly.","solutions":["Check the argument types passed to the function in the failing query and simplify/coerce them to a supported combination","Update getMultiComparisonFunc to handle the missing type combination","Strengthen the compile-time typecheck to reject unsupported mixes with a clear error instead of reaching the panic","File a Vitess bug with the query and argument types if hit via normal SQL"],"exampleFix":"// before\n\tif json > 0 {\n\t\treturn compareAllText\n\t}\n}\npanic(\"unexpected argument type\")\n// after\n\tif json > 0 {\n\t\treturn compareAllText\n\t}\n}\nreturn compareAllText // documented fallback, or return an error instead of panicking","handlingStrategy":"validation","validationCode":"// Coerce LEAST/GREATEST arguments to a uniform type family before evaluating\nfunc uniformArgTypes(args []sqltypes.Type) bool {\n\tfam := typeFamily(args[0])\n\tfor _, a := range args[1:] {\n\t\tif typeFamily(a) != fam {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":"func isSupportedArgMix(args []evalengine.eval) bool {\n\t// supported: all numeric, all temporal, or string/json mixes handled by compareAllText\n\treturn uniformArgTypes(typesOf(args)) || countJSONOrString(args) == len(args)\n}","tryCatchPattern":"func safeMultiCompare(fn string, args []evalengine.eval) (v evalengine.eval, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"%s arg-type panic: %v\", fn, r)\n\t\t}\n\t}()\n\treturn evalMultiCompare(fn, args)\n}","preventionTips":["Pass homogeneous argument types to LEAST/GREATEST/INTERVAL (CAST as needed)","Update getMultiComparisonFunc whenever adding new evalengine type kinds","Reject unsupported type mixes at compile time with clear errors","Add tests covering type-mix combinations for multi-arg functions"],"tags":["evalengine","panic","type-dispatch","least-greatest","comparison"],"backgroundTag":"unhandled-type-dispatch-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}