vitessio/vitess · error
unexpected comparison operator
Error message
unexpected comparison operator
What it means
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.
Source
Thrown at go/vt/vtgate/evalengine/expr_compare.go:475
case compareGT:
if swapped {
c.asm.Cmp_lt()
} else {
c.asm.Cmp_gt()
}
case compareGE:
if swapped {
c.asm.Cmp_le()
} else {
c.asm.Cmp_ge()
}
case compareNullSafeEQ:
c.asm.jumpDestination(skip2)
c.asm.Cmp_eq()
return cmptype, nil
default:
panic("unexpected comparison operator")
}
c.asm.jumpDestination(skip1, skip2)
return cmptype, nil
}
func evalInExpr(collationEnv *collations.Environment, lhs eval, rhs *evalTuple) (boolean, error) {
if lhs == nil {
return boolNULL, nil
}
var foundNull, found bool
for _, rtuple := range rhs.t {
numeric, isNull, err := evalCompareAll(lhs, rtuple, true, collationEnv)
if err != nil {
return boolNULL, err
}
if isNull {View on GitHub (pinned to 01a25a7d17)
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
Example fix
// before
case compareNullSafeEQ:
c.asm.jumpDestination(skip2)
c.asm.Cmp_eq()
return cmptype, nil
default:
panic("unexpected comparison operator")
// after
case compareNullSafeEQ:
c.asm.jumpDestination(skip2)
c.asm.Cmp_eq()
return cmptype, nil
case compareNewOp:
c.asm.jumpDestination(skip2)
c.asm.Cmp_new()
return cmptype, nil
default:
panic("unexpected comparison operator") Defensive patterns
Strategy: validation
Validate before calling
// Enumerate the valid comparison operators before constructing expressions
var validCompareOps = map[evalengine.ComparisonOp]bool{ /* EQ, NE, LT, LE, GT, GE, NullSafeEQ, ... */ }
func opIsValid(op evalengine.ComparisonOp) bool { return validCompareOps[op] } Type guard
func isKnownComparisonOp(op evalengine.ComparisonOp) bool {
return op >= evalengine.Equal && op <= evalengine.NullSafeEqual
} Try / catch
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("comparison compile panic: %v (operator %v)", r, expr.Operator)
}
}() Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- invalid comparison operator
- 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/eb564ec79ea0e7e5.
Report an issue: GitHub.