vitessio/vitess · error

unreachable

Error message

unreachable

What it means

evalTemporal.ToRawBytes serializes a temporal value by its SQL type (Date, Datetime, Timestamp, Time). Any other type reaching it hits default and panics "unreachable" — the type is expected to be one of the four temporal types by construction.

Source

Thrown at go/vt/vtgate/evalengine/eval_temporal.go:53

	prec uint8
	dt   datetime.DateTime
}

func (e *evalTemporal) Hash(h *vthash.Hasher) {
	h.Write16(hashPrefixDate)
	e.dt.Hash(h)
}

func (e *evalTemporal) ToRawBytes() []byte {
	switch e.t {
	case sqltypes.Date:
		return e.dt.Date.Format()
	case sqltypes.Datetime, sqltypes.Timestamp:
		return e.dt.Format(e.prec)
	case sqltypes.Time:
		return e.dt.Time.Format(e.prec)
	default:
		panic("unreachable")
	}
}

func (e *evalTemporal) SQLType() sqltypes.Type {
	return e.t
}

func (e *evalTemporal) Size() int32 {
	return int32(e.prec)
}

func (e *evalTemporal) Scale() int32 {
	return 0
}

func (e *evalTemporal) toInt64() int64 {
	switch e.SQLType() {
	case sqltypes.Date:

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Validate the sqltypes.Type when constructing evalTemporal so only Date/Datetime/Timestamp/Time are accepted
  2. Add the new temporal type to the switch if a new one was introduced
  3. Check the value's type before calling addInterval/ToRawBytes

Example fix

// before
panic("unreachable")
// after
default:
    return e.dt.Format(e.prec) // or return an error for unknown types
Defensive patterns

Strategy: validation

Validate before calling

switch t {
case sqltypes.Date, sqltypes.Datetime, sqltypes.Timestamp, sqltypes.Time:
    // ok
default:
    return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v is not a temporal type", t)
}

Type guard

func isTemporalType(t sqltypes.Type) bool {
    switch t {
    case sqltypes.Date, sqltypes.Datetime, sqltypes.Timestamp, sqltypes.Time:
        return true
    default:
        return false
    }
}

Try / catch

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

Prevention

When it happens

Trigger: An *evalTemporal constructed with an unexpected sqltypes.Type (e.g. someone built it with a non-temporal type), then ToRawBytes is called — e.g. from addInterval during date arithmetic.

Common situations: Refactors constructing evalTemporal with a raw type from a query result not validated as temporal; new temporal-like SQL types not yet handled.

Related errors


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