vitessio/vitess · error

unexpected Numeric type

Error message

unexpected Numeric type

What it means

Panic in the unary-minus compiler path of `compile`. The switch converts the argument's compile-time type into the negation result type: Int->Int/Uint->Float64/Decimal->Decimal, each emitting a matching ASM op. A numeric type outside that set (or an unset type) reaches `panic("unexpected Numeric type")`, meaning the type-coercion stage upstream let a non-negatable type through.

Source

Thrown at go/vt/vtgate/evalengine/expr_arithmetic.go:538

			neg = sqltypes.Int64
			c.asm.Neg_i()
		}
	case sqltypes.Uint64:
		if arg.Flag&flagHex != 0 {
			neg = sqltypes.Float64
			c.asm.Neg_hex()
		} else {
			neg = sqltypes.Int64
			c.asm.Neg_u()
		}
	case sqltypes.Float64:
		neg = sqltypes.Float64
		c.asm.Neg_f()
	case sqltypes.Decimal:
		neg = sqltypes.Decimal
		c.asm.Neg_d()
	default:
		panic("unexpected Numeric type")
	}

	c.asm.jumpDestination(skip)
	return ctype{
		Type:  neg,
		Flag:  nullableFlags(arg.Flag),
		Size:  arg.Size,
		Scale: arg.Scale,
		Col:   collationNumeric,
	}, nil
}

func nullableFlags(flag typeFlag) typeFlag {
	return flag & (flagNull | flagNullable)
}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Determine the argument type from the failing query and add the corresponding case (and ASM op) to the switch
  2. Tighten upstream coercion so only Int/Uint/Float64/Decimal reach this path
  3. Replace the panic with a wrapped internal error for graceful query failure
  4. Upgrade to a release that handles the type

Example fix

// before
default:
    panic("unexpected Numeric type")
// after
default:
    return ctype{}, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "cannot negate type %v", arg.Type)
Defensive patterns

Strategy: type-guard

Validate before calling

switch arg.Type {
case sqltypes.Int64, sqltypes.Uint64, sqltypes.Float64, sqltypes.Decimal:
    // ok
default:
    return ctype{}, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unary minus on unsupported type %v", arg.Type)
}

Type guard

func isNegatableNumeric(t sqltypes.Type) bool {
    switch t {
    case sqltypes.Int8, sqltypes.Int16, sqltypes.Int24, sqltypes.Int32, sqltypes.Int64,
        sqltypes.Uint8, sqltypes.Uint16, sqltypes.Uint24, sqltypes.Uint32, sqltypes.Uint64,
        sqltypes.Float32, sqltypes.Float64, sqltypes.Decimal:
        return true
    }
    return false
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "negation compile panic: %v", r)
    }
}()

Prevention

When it happens

Trigger: Compiling `-expr` where the argument's resolved type is not one of the numeric types the switch expects (e.g. a newly added numeric type, or a type left at 0).

Common situations: Development-time issue after introducing new numeric sqltypes or changing coercion rules; on a released binary it would manifest as a vtgate panic for a specific unary-minus query.

Related errors


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