{"record":{"id":"eb97c31bc9ba9a07","repo":"vitessio/vitess","slug":"unreacheable","errorCode":null,"errorMessage":"unreacheable","messagePattern":"unreacheable","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/eval.go","lineNumber":196,"sourceCode":"\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\n\tcase sqltypes.Float32, sqltypes.Float64:\n\t\tf, _ := evalToFloat(e)\n\t\treturn f, nil\n\tcase sqltypes.Int8, sqltypes.Int16, sqltypes.Int32, sqltypes.Int64:\n\t\treturn evalToInt64(e), nil\n\tcase sqltypes.Uint8, sqltypes.Uint16, sqltypes.Uint32, sqltypes.Uint64:\n\t\treturn evalToInt64(e).toUint64(), nil\n\tcase sqltypes.Date:\n\t\treturn evalToDate(e, now, allowZero), nil\n\tcase sqltypes.Datetime, sqltypes.Timestamp:\n\t\treturn evalToDateTime(e, int(size), now, allowZero), nil\n\tcase sqltypes.Time:\n\t\treturn evalToTime(e, int(size)), nil\n\tdefault:\n\t\treturn nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, \"Unsupported type conversion: %s\", typ.String())\n\t}","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/eval.go#L178-L214","documentation":"In evalCoerce, Char/VarChar coercions are handled earlier by an explicit evalToVarchar branch (which also swaps in the target collation). The later switch therefore treats a Char/VarChar target as unreachable and panics. Reaching it means control flow changed — e.g. the early branch was bypassed or a caller coerces to Char/VarChar through a path that no longer routes through the early return.","triggerScenarios":"Refactoring evalCoerce so the early `typ == VarChar || typ == Char` return no longer catches all string coercions (or a new call path passes sqltypes.Char/sqltypes.VarChar expecting the switch to handle it).","commonSituations":"Engine development: modifying coercion logic in eval.go or adding a coercion call site that forgot the explicit VARCHAR path; not reachable by end users on stock Vitess.","solutions":["Route the call through the explicit VARCHAR coercion path (evalToVarchar) instead of the generic switch","If the early branch was refactored, restore handling for Char/VarChar in the switch by delegating to evalToVarchar(e, col, false)","Add a regression test coercing to VarChar/Char to cover the path"],"exampleFix":"// before\ncase sqltypes.Char, sqltypes.VarChar:\n\tpanic(\"unreacheable\")\n// after\ncase sqltypes.Char, sqltypes.VarChar:\n\treturn evalToVarchar(e, col, false), nil","handlingStrategy":"type-guard","validationCode":"// Go: only call evalCoerce's switch for non-CHAR/VARCHAR targets\nif typ == sqltypes.Char || typ == sqltypes.VarChar {\n\treturn evalToVarchar(e, col, false), nil\n}","typeGuard":"func isCharTarget(typ sqltypes.Type) bool {\n\treturn typ == sqltypes.Char || typ == sqltypes.VarChar\n}","tryCatchPattern":"func safeCoerceToChar(e eval, 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, \"char coercion failed: %v\", r)\n\t\t}\n\t}()\n\treturn evalToVarchar(e, col, false), nil\n}","preventionTips":["Never rely on the fall-through switch for CHAR/VARCHAR; always use the explicit early branch","Add a unit test coercing values to both Char and VarChar","When refactoring evalCoerce, keep the early string branch and the switch's unreachable guard consistent"],"tags":["go","panic","evalengine","coercion"],"backgroundTag":"unreachable-code-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}