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
- Validate the sqltypes.Type when constructing evalTemporal so only Date/Datetime/Timestamp/Time are accepted
- Add the new temporal type to the switch if a new one was introduced
- 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
- Validate the SQL type when constructing evalTemporal, rejecting non-temporal types
- Update temporal switches when new temporal types are introduced
- Embed e.SQLType() in unreachable panics for faster diagnosis
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
- malformed hex literal from parser
- bad unsigned integer type
- bad type aggregation for signed/unsigned types
- unreachable
- unhandled case: evalIsTruthy
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/0778f1dcc2e6ad75.
Report an issue: GitHub.