{"record":{"id":"80f4af6976943a6b","repo":"vitessio/vitess","slug":"panic-err-80f4af","errorCode":null,"errorMessage":"panic(err)","messagePattern":"panic\\(err\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/eval_tuple.go","lineNumber":52,"sourceCode":"\tfor _, value := range values {\n\t\tval := sqltypes.ProtoToValue(value)\n\n\t\te, err := valueToEval(val, typedCoercionCollation(val.Type(), collations.CollationForType(val.Type(), collation)), nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tevals = append(evals, e)\n\t}\n\n\treturn &evalTuple{t: evals}, nil\n}\n\nfunc (e *evalTuple) ToRawBytes() []byte {\n\tvals := make([]sqltypes.Value, 0, len(e.t))\n\tfor _, e2 := range e.t {\n\t\tv, err := sqltypes.NewValue(e2.SQLType(), e2.ToRawBytes())\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tvals = append(vals, v)\n\t}\n\treturn sqltypes.TupleToProto(vals).Value\n}\n\nfunc (e *evalTuple) SQLType() sqltypes.Type {\n\treturn sqltypes.Tuple\n}\n\nfunc (e *evalTuple) Size() int32 {\n\treturn 0\n}\n\nfunc (e *evalTuple) Scale() int32 {\n\treturn 0\n}\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/eval_tuple.go#L34-L70","documentation":"`evalTuple.ToRawBytes()` serializes a tuple of inner values back into a proto-encoded tuple. Each inner value is re-wrapped with `sqltypes.NewValue(type, bytes)`; if that validation fails (type/bytes mismatch for an element), the code panics with the underlying error. This indicates an internal inconsistency — an element in the evalTuple cannot be represented as a valid sqltypes.Value.","triggerScenarios":"Calling ToRawBytes() on an evalTuple containing an element whose SQLType/bytes combination is rejected by sqltypes.NewValue (e.g. an invalid or unsupported type produced by the engine).","commonSituations":"Hit during Vitess development when new eval types are added to tuples without ensuring NewValue accepts their serialized form; not reachable from normal SQL execution.","solutions":["Inspect the tuple element that fails NewValue and fix how its type/bytes are produced","Validate inner values when building evalTuple rather than at serialization time","Replace the raw panic with a wrapped error at the public API boundary","Report as a Vitess bug if reproducible on a released version"],"exampleFix":"// before\nif err != nil {\n    panic(err)\n}\n// after\nif err != nil {\n    panic(vterrors.Wrapf(err, \"cannot serialize tuple element of type %v\", e2.SQLType()))","handlingStrategy":"type-guard","validationCode":"for _, e2 := range e.t {\n    if _, err := sqltypes.NewValue(e2.SQLType(), e2.ToRawBytes()); err != nil {\n        return vterrors.Wrapf(err, \"invalid tuple element type %v\", e2.SQLType())\n    }\n}","typeGuard":"func isValidTupleElement(v evalengine.Eval) bool {\n    _, err := sqltypes.NewValue(v.SQLType(), v.ToRawBytes())\n    return err == nil\n}","tryCatchPattern":"func safeToRawBytes(e *evalengine.EvalTuple) (b []byte, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, \"tuple serialization panic: %v\", r)\n        }\n    }()\n    return e.ToRawBytes(), nil\n}","preventionTips":["Validate element types when constructing evalTuple, not at serialization","Only place engine-produced eval values into tuples","Add a unit test serializing tuples of every supported eval type"],"tags":["go","panic","serialization","evalengine","tuple"],"backgroundTag":"unreachable-invariant-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}