{"record":{"id":"eb564ec79ea0e7e5","repo":"vitessio/vitess","slug":"unexpected-comparison-operator","errorCode":null,"errorMessage":"unexpected comparison operator","messagePattern":"unexpected comparison operator","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/expr_compare.go","lineNumber":475,"sourceCode":"\tcase compareGT:\n\t\tif swapped {\n\t\t\tc.asm.Cmp_lt()\n\t\t} else {\n\t\t\tc.asm.Cmp_gt()\n\t\t}\n\tcase compareGE:\n\t\tif swapped {\n\t\t\tc.asm.Cmp_le()\n\t\t} else {\n\t\t\tc.asm.Cmp_ge()\n\t\t}\n\tcase compareNullSafeEQ:\n\t\tc.asm.jumpDestination(skip2)\n\t\tc.asm.Cmp_eq()\n\t\treturn cmptype, nil\n\n\tdefault:\n\t\tpanic(\"unexpected comparison operator\")\n\t}\n\n\tc.asm.jumpDestination(skip1, skip2)\n\treturn cmptype, nil\n}\n\nfunc evalInExpr(collationEnv *collations.Environment, lhs eval, rhs *evalTuple) (boolean, error) {\n\tif lhs == nil {\n\t\treturn boolNULL, nil\n\t}\n\n\tvar foundNull, found bool\n\tfor _, rtuple := range rhs.t {\n\t\tnumeric, isNull, err := evalCompareAll(lhs, rtuple, true, collationEnv)\n\t\tif err != nil {\n\t\t\treturn boolNULL, err\n\t\t}\n\t\tif isNull {","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/expr_compare.go#L457-L493","documentation":"During comparison-expression compilation, the compiler switches over all comparison operator kinds; the null-safe-equality case (compareNullSafeEQ) is the last handled one, and anything after it hits this panic. It means an unrecognized comparison operator value reached the compiler, breaking the assumption that the typechecker/IR only emits known operators.","triggerScenarios":"Compiling a ComparisonExpr whose Operator field holds an enum value not covered by the switch (e.g., a newly added operator without a compile case, or an invalid zero/garbage value from a manually constructed IR node).","commonSituations":"Evalengine development adding new comparison operators; test code constructing ComparisonExpr with wrong constants; version-skew builds where parser emits an operator the compiler does not know.","solutions":["Log/inspect the offending operator value to identify the unhandled kind","Add a compile case for the new operator in expr_compare.go","Validate operators at IR-construction time so invalid values fail early with a clear error","Ensure parser and evalengine are built from the same version"],"exampleFix":"// before\ncase compareNullSafeEQ:\n\tc.asm.jumpDestination(skip2)\n\tc.asm.Cmp_eq()\n\treturn cmptype, nil\ndefault:\n\tpanic(\"unexpected comparison operator\")\n// after\ncase compareNullSafeEQ:\n\tc.asm.jumpDestination(skip2)\n\tc.asm.Cmp_eq()\n\treturn cmptype, nil\ncase compareNewOp:\n\tc.asm.jumpDestination(skip2)\n\tc.asm.Cmp_new()\n\treturn cmptype, nil\ndefault:\n\tpanic(\"unexpected comparison operator\")","handlingStrategy":"validation","validationCode":"// Enumerate the valid comparison operators before constructing expressions\nvar validCompareOps = map[evalengine.ComparisonOp]bool{ /* EQ, NE, LT, LE, GT, GE, NullSafeEQ, ... */ }\nfunc opIsValid(op evalengine.ComparisonOp) bool { return validCompareOps[op] }","typeGuard":"func isKnownComparisonOp(op evalengine.ComparisonOp) bool {\n\treturn op >= evalengine.Equal && op <= evalengine.NullSafeEqual\n}","tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\terr = fmt.Errorf(\"comparison compile panic: %v (operator %v)\", r, expr.Operator)\n\t}\n}()","preventionTips":["Construct ComparisonExpr only via the translation layer, not manually","Update the compile switch in the same commit as any new operator","Add exhaustive-switch lint and operator round-trip tests","Avoid version-skewed builds"],"tags":["evalengine","panic","comparison-operator"],"backgroundTag":"unhandled-switch-case-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}