{"record":{"id":"e0c1d9dd0aa0e431","repo":"vitessio/vitess","slug":"type-t-not-supported-as-bind-var-v","errorCode":null,"errorMessage":"type %T not supported as bind var: %v","messagePattern":"type %T not supported as bind var: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/sqltypes/bind_variables.go","lineNumber":331,"sourceCode":"\t\treturn bv, nil\n\tcase []Value:\n\t\tbv := &querypb.BindVariable{\n\t\t\tType:   querypb.Type_TUPLE,\n\t\t\tValues: make([]*querypb.Value, len(v)),\n\t\t}\n\t\tvalues := make([]querypb.Value, len(v))\n\t\tfor i, lv := range v {\n\t\t\tlbv, err := BuildBindVariable(lv)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvalues[i].Type = lbv.Type\n\t\t\tvalues[i].Value = lbv.Value\n\t\t\tbv.Values[i] = &values[i]\n\t\t}\n\t\treturn bv, nil\n\t}\n\treturn nil, fmt.Errorf(\"type %T not supported as bind var: %v\", v, v)\n}\n\n// ValidateBindVariables validates a map[string]*querypb.BindVariable.\nfunc ValidateBindVariables(bv map[string]*querypb.BindVariable) error {\n\tfor k, v := range bv {\n\t\tif err := ValidateBindVariable(v); err != nil {\n\t\t\treturn fmt.Errorf(\"%s: %v\", k, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// ValidateBindVariable returns an error if the bind variable has inconsistent\n// fields.\nfunc ValidateBindVariable(bv *querypb.BindVariable) error {\n\tif bv == nil {\n\t\treturn errors.New(\"bind variable is nil\")\n\t}","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/sqltypes/bind_variables.go#L313-L349","documentation":"Returned by bind variable conversion code when a value of an unsupported Go type is passed as a bind variable; only the types known to sqltypes (integers, strings, []byte, bool, float, sqltypes.Value, query.BindVariable, etc.) are accepted.","triggerScenarios":"Passing an unsupported Go type (struct, map, channel, func, nil without a type, nested unsupported slice elements) to BuildBindVariable, directly or via BuildBindVariables.","commonSituations":"Passing protobuf messages or structs instead of scalars; passing typed-nil pointers; passing slices of unsupported element types; values produced by generic deserialization (JSON/YAML) that need conversion.","solutions":["Convert the value to a supported type before binding: string, int/uint/float variants, []byte, time.Time, or []T of a supported scalar","For nil, use a typed value such as sqltypes.NULL via an explicit conversion","For lists, build a []string or []int64 etc. of a supported element type","Inspect %T in the message to identify exactly which type leaked in"],"exampleFix":"// before\nbindVars[\"filter\"] = struct{ A int }{A: 1}\n// after\nbindVars[\"filter\"] = 1 // or serialize to []byte / JSON string if intended","handlingStrategy":"type-guard","validationCode":"if !isBindable(v) { return fmt.Errorf(\"cannot bind %T\", v) }","typeGuard":"func isBindable(v interface{}) bool {\n\tswitch v.(type) {\n\tcase nil, string, []byte, int, int8, int16, int32, int64,\n\t\tuint, uint8, uint16, uint32, uint64, float32, float64,\n\t\ttime.Time, *querypb.BindVariable:\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"bv, err := sqltypes.BuildBindVariable(v)\nif err != nil {\n\treturn vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, \"bind var %v: %v\", v, err)\n}","preventionTips":["Convert custom types at the boundary to scalars/[]byte before binding","Use explicit serialization (JSON/protobuf bytes) for complex values","Avoid interface{} plumbing that lets arbitrary types reach bind calls"],"tags":["go","sql","bind-variables","type-error"],"backgroundTag":"unsupported-bind-variable-type","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}