{"record":{"id":"b82f27529b3be982","repo":"go-sql-driver/mysql","slug":"unsupported-type-t-a-slice-of-s","errorCode":null,"errorMessage":"unsupported type %T, a slice of %s","messagePattern":"unsupported type %T, a slice of (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"statement.go","lineNumber":206,"sourceCode":"\t\t} else {\n\t\t\treturn c.ConvertValue(rv.Elem().Interface())\n\t\t}\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn rv.Int(), nil\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn rv.Uint(), nil\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn rv.Float(), nil\n\tcase reflect.Bool:\n\t\treturn rv.Bool(), nil\n\tcase reflect.Slice:\n\t\tswitch t := rv.Type(); {\n\t\tcase t == jsonType:\n\t\t\treturn v, nil\n\t\tcase t.Elem().Kind() == reflect.Uint8:\n\t\t\treturn rv.Bytes(), nil\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unsupported type %T, a slice of %s\", v, t.Elem().Kind())\n\t\t}\n\tcase reflect.String:\n\t\treturn rv.String(), nil\n\t}\n\treturn nil, fmt.Errorf(\"unsupported type %T, a %s\", v, rv.Kind())\n}\n\nvar valuerReflectType = reflect.TypeFor[driver.Valuer]()\n\n// callValuerValue returns vr.Value(), with one exception:\n// If vr.Value is an auto-generated method on a pointer type and the\n// pointer is nil, it would panic at runtime in the panicwrap\n// method. Treat it like nil instead.\n//\n// This is so people can implement driver.Value on value types and\n// still use nil pointers to those types to mean nil/NULL, just like\n// string/*string.\n//","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/statement.go#L188-L224","documentation":"ConvertValue only accepts byte slices ([]byte) and json.RawMessage among slice types; a slice of any other element kind is unsupported and rejected, naming the element Kind in the message.","triggerScenarios":"Passing []int, []string, []MyType, or any non-byte slice as a prepared-statement argument.","commonSituations":"Expecting the driver to expand/serialize arrays automatically; passing a slice where a single value was intended.","solutions":["Serialize the slice yourself (e.g. JSON-encode to []byte/string) before passing it.","Expand the slice into one '?' placeholder per element and pass each element separately.","Store the collection as JSON/TEXT in a single column."],"exampleFix":"// before\nstmt.Exec([]string{\"a\",\"b\"}) // SQL: INSERT INTO t(tags) VALUES (?)\n// after (JSON-encode)\nb, _ := json.Marshal([]string{\"a\",\"b\"})\nstmt.Exec(string(b))","handlingStrategy":"validation","validationCode":"// Reject non-byte slices before Exec.\nfunc okArg(v any) bool {\n    rv := reflect.ValueOf(v)\n    if rv.Kind() == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8 {\n        return false\n    }\n    return true\n}","typeGuard":"func isSupportedSlice(v any) bool {\n    rv := reflect.ValueOf(v)\n    if rv.Kind() != reflect.Slice { return true }\n    return rv.Type().Elem().Kind() == reflect.Uint8 || rv.Type() == reflect.TypeOf(json.RawMessage{})\n}","tryCatchPattern":"// Returned from Exec/Query for unsupported slice arguments.\nif _, err := stmt.Exec(args...); err != nil {\n    if strings.Contains(err.Error(), \"a slice of\") {\n        // JSON-encode or expand the slice\n    }\n}","preventionTips":["Don't pass non-byte slices to prepared statements; serialize first.","Expand arrays into multiple placeholders when feasible.","Add a pre-Exec guard rejecting unsupported slice kinds."],"tags":["go","mysql","types","slice","prepared-statement"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}