vitessio/vitess · error
unexpected arithmetic operator
Error message
unexpected arithmetic operator
What it means
This panic comes from the evalengine's bit-expression compiler (compileBinary) when it encounters an *opBit* AST node type it does not recognize. It marks an internal invariant violation: the parser produced a bit operator node that the compiler's exhaustive switch was never taught to handle. It is not triggered by user SQL directly, but by a mismatch between the sqlparser AST and the evalengine IR translation layer.
Source
Thrown at go/vt/vtgate/evalengine/expr_bit.go:330
c.asm.jumpDestination(skip1, skip2)
return ctype{Type: sqltypes.Uint64, Flag: nullableFlags(lt.Flag | rt.Flag), Col: collationNumeric}, nil
}
func (expr *BitwiseExpr) compile(c *compiler) (ctype, error) {
switch expr.Op.(type) {
case *opBitAnd:
return expr.compileBinary(c, c.asm.BitOp_and_bb, c.asm.BitOp_and_uu)
case *opBitOr:
return expr.compileBinary(c, c.asm.BitOp_or_bb, c.asm.BitOp_or_uu)
case *opBitXor:
return expr.compileBinary(c, c.asm.BitOp_xor_bb, c.asm.BitOp_xor_uu)
case *opBitShl:
return expr.compileShift(c, -1)
case *opBitShr:
return expr.compileShift(c, 1)
default:
panic("unexpected arithmetic operator")
}
}
var (
_ opBitBinary = (*opBitAnd)(nil)
_ opBitBinary = (*opBitOr)(nil)
_ opBitBinary = (*opBitXor)(nil)
_ opBitShift = (*opBitShl)(nil)
_ opBitShift = (*opBitShr)(nil)
)
View on GitHub (pinned to 01a25a7d17)
Solutions
- Check the evalengine IR type that reached compileBinary and confirm which opBitBinary variant is unhandled
- Add a case for the missing operator in compileBinary in go/vt/vtgate/evalengine/expr_bit.go, mapping it to the appropriate BitOp asm opcode
- Regenerate/rebuild so parser-generated IR and the compiler switch are in sync
- If seen on a released build without local changes, file a Vitess bug with the failing query
Example fix
// before
case *opBitShr:
return expr.compileShift(c, 1)
default:
panic("unexpected arithmetic operator")
// after
case *opBitShr:
return expr.compileShift(c, 1)
case *opBitNewOp:
return expr.compileBinary(c, c.asm.BitOp_new_bb, c.asm.BitOp_new_uu)
default:
panic("unexpected arithmetic operator") Defensive patterns
Strategy: validation
Validate before calling
// Before compiling custom IR, ensure the bit op is a known variant
func isKnownBitOp(op evalengine.IR) bool {
switch op.(type) {
case *evalengine.BitAnd, *evalengine.BitOr, *evalengine.BitXor, *evalengine.BitShl, *evalengine.BitShr:
return true
}
return false
} Type guard
if bo, ok := expr.(*evalengine.BitBinaryOp); ok && isKnownBitOp(bo) { /* safe to compile */ } Try / catch
func safeCompile(e evalengine.IR) (ct evalengine.ctype, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("compile panic: %v", r)
}
}()
return e.compile(compiler)
} Prevention
- When adding opBitBinary variants, update compileBinary's switch in the same PR
- Add exhaustive-switch linters (exhaustive) for IR compile switches
- Add unit tests compiling every bit operator IR type
- Keep sqlparser and evalengine built from the same commit
When it happens
Trigger: Calling compiler.compile on an expression IR tree that contains an unregistered opBitBinary variant (i.e., a type implementing opBitBinary that is not *opBitAnd, *opBitOr, *opBitXor, *opBitShl, or *opBitShr). Practically this happens only when new bit operators are added to the IR without updating compileBinary's switch.
Common situations: Developers extending the evalengine with a new bit operator; running against a Vitess build where parser and evalengine were updated out of sync (mixed-version or patched build); fuzzing or constructing IR nodes programmatically in tests.
Related errors
- bad unsigned integer type
- bad type aggregation for signed/unsigned types
- unreachable
- unreachable
- This should never happen.
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/412938650daf27c0.
Report an issue: GitHub.