go-sql-driver/mysql · error
unsupported type %T, a %s
Error message
unsupported type %T, a %s
What it means
The driver's converter (statement.go:211) fell through its entire type switch: the value's reflect.Kind is none of pointer, integer, unsigned, float, bool, slice, or string, and the type does not implement driver.Valuer. This covers structs, maps, arrays, chans, and funcs that the driver cannot serialize.
Source
Thrown at statement.go:211
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return rv.Uint(), nil
case reflect.Float32, reflect.Float64:
return rv.Float(), nil
case reflect.Bool:
return rv.Bool(), nil
case reflect.Slice:
switch t := rv.Type(); {
case t == jsonType:
return v, nil
case t.Elem().Kind() == reflect.Uint8:
return rv.Bytes(), nil
default:
return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind())
}
case reflect.String:
return rv.String(), nil
}
return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
}
var valuerReflectType = reflect.TypeFor[driver.Valuer]()
// callValuerValue returns vr.Value(), with one exception:
// If vr.Value is an auto-generated method on a pointer type and the
// pointer is nil, it would panic at runtime in the panicwrap
// method. Treat it like nil instead.
//
// This is so people can implement driver.Value on value types and
// still use nil pointers to those types to mean nil/NULL, just like
// string/*string.
//
// This is an exact copy of the same-named unexported function from the
// database/sql package.
func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
rv.IsNil() &&View on GitHub (pinned to c426bd9379)
Solutions
- Marshal structs/maps to JSON and pass the resulting []byte.
- Implement driver.Valuer on the custom type so Value() returns a base driver.Value.
- Extract the specific primitive field(s) needed and pass those individually.
Example fix
// before
db.Exec("INSERT INTO t(data) VALUES(?)", myStruct)
// after
b, _ := json.Marshal(myStruct)
db.Exec("INSERT INTO t(data) VALUES(?)", b) Defensive patterns
Strategy: type-guard
Validate before calling
func isSupportedArg(v any) bool {
if v == nil { return true }
if _, ok := v.(driver.Valuer); ok { return true }
switch reflect.ValueOf(v).Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
return true
}
return false
} Type guard
func supportedKind(k reflect.Kind) bool {
switch k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64, reflect.Bool, reflect.String:
return true
}
return false
} Try / catch
if _, err := db.Exec(q, v); err != nil {
if strings.Contains(err.Error(), "unsupported type") {
// marshal to []byte or implement driver.Valuer
}
} Prevention
- Do not pass structs/maps directly; marshal them first.
- Implement driver.Valuer for reusable custom types.
- Extract primitive fields rather than passing whole structs.
When it happens
Trigger: Passing a struct or map directly as an argument; passing a chan/func value; a nil interface wrapping an unhandled concrete type.
Common situations: Expecting automatic JSON serialization of a struct; passing a whole map as a parameter; submitting a domain object without extracting primitive fields.
Related errors
- non-Value type %T returned from Value
- unsupported type %T, a slice of %s
- cannot convert type: %T
- mysql: driver does not support the use of Named Parameters
- mysql: unsupported isolation level: %v
AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04).
Data as JSON: /data/errors/c7a5dee657dea184.json.
Report an issue: GitHub.