vitessio/vitess · error
called EvalResult.truncate on non-quoted
Error message
called EvalResult.truncate on non-quoted
What it means
evalBytes.truncateInPlace truncates a string/binary value to a given size. Text and binary values can be byte/charset-aware truncated, but other flavors of evalBytes (e.g. JSON or enum-backed strings stored as evalBytes) have no defined truncation, so the default case panics. It signals the truncate call was made on a value kind that doesn't support quoted/truncation semantics.
Source
Thrown at go/vt/vtgate/evalengine/eval_bytes.go:181
func (e *evalBytes) withCollation(col collations.TypedCollation) *evalBytes {
return newEvalRaw(e.SQLType(), e.bytes, col)
}
func (e *evalBytes) truncateInPlace(size int) {
switch tt := e.SQLType(); {
case sqltypes.IsBinary(tt):
if size > len(e.bytes) {
pad := make([]byte, size)
copy(pad, e.bytes)
e.bytes = pad
} else {
e.bytes = e.bytes[:size]
}
case sqltypes.IsText(tt):
collation := colldata.Lookup(e.col.Collation)
e.bytes = charset.Slice(collation.Charset(), e.bytes, 0, size)
default:
panic("called EvalResult.truncate on non-quoted")
}
}
func (e *evalBytes) toDateBestEffort() datetime.DateTime {
if t, _, _ := datetime.ParseDateTime(e.string(), -1); !t.IsZero() {
return t
}
if t, _ := datetime.ParseDate(e.string()); !t.IsZero() {
return datetime.DateTime{Date: t}
}
return datetime.DateTime{}
}
func (e *evalBytes) parseNumericBytes(number *[8]byte) bool {
raw := e.bytes
if l := len(raw); l > 8 {
for _, b := range raw[:l-8] {
if b != 0 {View on GitHub (pinned to 01a25a7d17)
Solutions
- Check e.SQLType() before calling truncateInPlace and skip or convert non-text/binary values
- Add a case in truncateInPlace for the new evalBytes flavor if truncation is meaningful for it
- File a Vitess issue with the crashing CAST/coercion expression if it reproduces on unmodified code
Example fix
// before
if e.SQLType() == sqltypes.VarChar {
e.truncateInPlace(size, col)
}
// after
tt := e.SQLType()
if sqltypes.IsText(tt) || sqltypes.IsBinary(tt) {
e.truncateInPlace(size, col)
} Defensive patterns
Strategy: type-guard
Validate before calling
// Go: check the type is truncatable before calling
tt := e.SQLType()
if !sqltypes.IsText(tt) && !sqltypes.IsBinary(tt) {
return // skip truncation or convert first
} Type guard
func isTruncatable(e *evalBytes) bool {
tt := e.SQLType()
return sqltypes.IsText(tt) || sqltypes.IsBinary(tt)
} Try / catch
func safeTruncate(e *evalBytes, size int32, col collations.ID) (err error) {
defer func() {
if r := recover(); r != nil {
err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "truncate failed: %v", r)
}
}()
e.truncateInPlace(size, col)
return nil
} Prevention
- Check SQLType is text/binary before any truncation call
- When storing a new value flavor in evalBytes, audit all methods that switch on SQLType
- Prefer returning vterrors from coercion helpers over panicking on unsupported flavors
When it happens
Trigger: Coercion/casting machinery calling truncateInPlace on an evalBytes whose SQLType is neither binary nor text — e.g. after a type was widened/changed upstream (say a JSON value held in evalBytes) and the caller didn't re-check the type before truncating.
Common situations: Engine development: adding new cast targets or changing how values are stored in evalBytes; end users may see this as a vtgate crash on a specific CAST/coercion query.
Related errors
- EvalResult.coerce with no collation
- unreacheable
- malformed hex literal from parser
- bad unsigned integer type
- bad type aggregation for signed/unsigned types
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/303eaa69b73330f4.
Report an issue: GitHub.