{"record":{"id":"a2d4431c25a3dc0b","repo":"vitessio/vitess","slug":"evalresult-coerce-with-no-collation","errorCode":null,"errorMessage":"EvalResult.coerce with no collation","messagePattern":"EvalResult\\.coerce with no collation","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/eval.go","lineNumber":180,"sourceCode":"\t\t\treturn makeboolean(bit.i != 0)\n\t\t}\n\t\tf, _ := fastparse.ParseFloat64(e.string())\n\t\treturn makeboolean(f != 0.0)\n\tcase *evalJSON:\n\t\treturn makeboolean(e.ToBoolean())\n\tcase *evalTemporal:\n\t\treturn makeboolean(!e.isZero())\n\tdefault:\n\t\tpanic(\"unhandled case: evalIsTruthy\")\n\t}\n}\n\nfunc evalCoerce(e eval, typ sqltypes.Type, size, scale int32, col collations.ID, now time.Time, allowZero bool) (eval, error) {\n\tif e == nil {\n\t\treturn nil, nil\n\t}\n\tif col == collations.Unknown {\n\t\tpanic(\"EvalResult.coerce with no collation\")\n\t}\n\tif typ == sqltypes.VarChar || typ == sqltypes.Char {\n\t\t// if we have an explicit VARCHAR coercion, always force it so the collation is replaced in the target\n\t\treturn evalToVarchar(e, col, false)\n\t}\n\tif e.SQLType() == typ && e.Size() == size && e.Scale() == scale {\n\t\t// nothing to be done here\n\t\treturn e, nil\n\t}\n\tswitch typ {\n\tcase sqltypes.Null:\n\t\treturn nil, nil\n\tcase sqltypes.Binary, sqltypes.VarBinary:\n\t\treturn evalToBinary(e), nil\n\tcase sqltypes.Char, sqltypes.VarChar:\n\t\tpanic(\"unreacheable\")\n\tcase sqltypes.Decimal:\n\t\treturn evalToDecimal(e, 0, 0), nil","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/eval.go#L162-L198","documentation":"evalCoerce converts an evaluated value to a target type, and character coercions need a concrete collation ID to pick the target charset. If col == collations.Unknown it panics because coercing to a string type without knowing the collation is meaningless. It is an internal guard: callers must resolve a real collation (or not request a string coercion) before calling evalCoerce.","triggerScenarios":"Calling evalCoerce with col=collations.Unknown while typ (or the value's coercion path) resolves to a character type; e.g. building a coercion plan where the collation merge step was skipped or returned Unknown for an unsupported/invalid collation.","commonSituations":"Queries involving columns or literals with collations unsupported by the configured collation environment, hitting paths that pass collations.Unknown downstream into evalCoerce; also hit by plugin/extension code constructing coercions manually.","solutions":["Resolve the collation before coercing: use the connection/environment default collation when mergeAndCoerceCollations yields Unknown","Ensure the query's charset/collation is supported by Vitess (check vtgate's collation environment and the column's DDL)","If writing engine code, guard the call: only pass Unknown for non-string target types, and return a vterrors error instead of reaching this panic"],"exampleFix":"// before\nreturn evalCoerce(e, sqltypes.VarChar, size, 0, collations.Unknown, now, false)\n// after\ncol := env.DefaultCollation() // or resolved merged collation\nreturn evalCoerce(e, sqltypes.VarChar, size, 0, col, now, false)","handlingStrategy":"validation","validationCode":"// Go: resolve a concrete collation before coercion\nif col == collations.Unknown {\n\tcol = env.DefaultCollation()\n}\nreturn evalCoerce(e, typ, size, scale, col, now, allowZero)","typeGuard":"func hasCollation(col collations.ID) bool {\n\treturn col != collations.Unknown && colldata.Lookup(col) != nil\n}","tryCatchPattern":"func safeCoerce(e eval, typ sqltypes.Type, col collations.ID) (out eval, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = vterrors.Errorf(vtrpcpb.Code_INTERNAL, \"coercion failed: %v\", r)\n\t\t}\n\t}()\n\treturn evalCoerce(e, typ, 0, 0, col, time.Now(), false)\n}","preventionTips":["Always run mergeAndCoerceCollations (or fall back to the connection default) before string coercion","Validate column DDL collations are supported by the Vitess collation environment at deploy time","Return vterrors with Code_UNKNOWN for unsupported collations instead of propagating collations.Unknown"],"tags":["go","panic","evalengine","collation","coercion"],"backgroundTag":"missing-collation-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}