{"record":{"id":"303eaa69b73330f4","repo":"vitessio/vitess","slug":"called-evalresult-truncate-on-non-quoted","errorCode":null,"errorMessage":"called EvalResult.truncate on non-quoted","messagePattern":"called EvalResult\\.truncate on non-quoted","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/eval_bytes.go","lineNumber":181,"sourceCode":"func (e *evalBytes) withCollation(col collations.TypedCollation) *evalBytes {\n\treturn newEvalRaw(e.SQLType(), e.bytes, col)\n}\n\nfunc (e *evalBytes) truncateInPlace(size int) {\n\tswitch tt := e.SQLType(); {\n\tcase sqltypes.IsBinary(tt):\n\t\tif size > len(e.bytes) {\n\t\t\tpad := make([]byte, size)\n\t\t\tcopy(pad, e.bytes)\n\t\t\te.bytes = pad\n\t\t} else {\n\t\t\te.bytes = e.bytes[:size]\n\t\t}\n\tcase sqltypes.IsText(tt):\n\t\tcollation := colldata.Lookup(e.col.Collation)\n\t\te.bytes = charset.Slice(collation.Charset(), e.bytes, 0, size)\n\tdefault:\n\t\tpanic(\"called EvalResult.truncate on non-quoted\")\n\t}\n}\n\nfunc (e *evalBytes) toDateBestEffort() datetime.DateTime {\n\tif t, _, _ := datetime.ParseDateTime(e.string(), -1); !t.IsZero() {\n\t\treturn t\n\t}\n\tif t, _ := datetime.ParseDate(e.string()); !t.IsZero() {\n\t\treturn datetime.DateTime{Date: t}\n\t}\n\treturn datetime.DateTime{}\n}\n\nfunc (e *evalBytes) parseNumericBytes(number *[8]byte) bool {\n\traw := e.bytes\n\tif l := len(raw); l > 8 {\n\t\tfor _, b := range raw[:l-8] {\n\t\t\tif b != 0 {","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/eval_bytes.go#L163-L199","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif e.SQLType() == sqltypes.VarChar {\n\te.truncateInPlace(size, col)\n}\n// after\ntt := e.SQLType()\nif sqltypes.IsText(tt) || sqltypes.IsBinary(tt) {\n\te.truncateInPlace(size, col)\n}","handlingStrategy":"type-guard","validationCode":"// Go: check the type is truncatable before calling\ntt := e.SQLType()\nif !sqltypes.IsText(tt) && !sqltypes.IsBinary(tt) {\n\treturn // skip truncation or convert first\n}","typeGuard":"func isTruncatable(e *evalBytes) bool {\n\ttt := e.SQLType()\n\treturn sqltypes.IsText(tt) || sqltypes.IsBinary(tt)\n}","tryCatchPattern":"func safeTruncate(e *evalBytes, size int32, col collations.ID) (err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = vterrors.Errorf(vtrpcpb.Code_INTERNAL, \"truncate failed: %v\", r)\n\t\t}\n\t}()\n\te.truncateInPlace(size, col)\n\treturn nil\n}","preventionTips":["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"],"tags":["go","panic","evalengine","string-handling","coercion"],"backgroundTag":"unhandled-type-switch-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}