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

  1. Check the evalengine IR type that reached compileBinary and confirm which opBitBinary variant is unhandled
  2. 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
  3. Regenerate/rebuild so parser-generated IR and the compiler switch are in sync
  4. 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 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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/412938650daf27c0. Report an issue: GitHub.