go-sql-driver/mysql · error
unsupported type %T, a
Error message
unsupported type %T, a %s
What it means
ConvertValue's final fallback: the value's reflect.Kind is not a pointer/int-family/uint-family/float/bool/slice/string - e.g. a struct, map, chan, func, array, or interface. The driver cannot serialize such a value to the MySQL protocol.
Solutions
- Pass a supported primitive field from the struct (e.g. s.ID instead of s).
- Implement driver.Valuer on the type to convert it to a supported primitive.
- Marshal the value to []byte/string (JSON) if it represents a complex payload.
Example fix
// before
type User struct{ ID int64; Name string }
stmt.Exec(User{1, "a"}) // SQL: INSERT INTO t VALUES (?)
// after
stmt.Exec(User{1, "a"}.ID) Defensive patterns
Strategy: validation
Validate before calling
// Reject unsupported kinds before Exec.
func supportedKind(v any) bool {
switch reflect.ValueOf(v).Kind() {
case reflect.Struct, reflect.Map, reflect.Chan, reflect.Func, reflect.Array:
return false
}
return true
} Type guard
func isConvertible(v any) bool {
if _, ok := v.(driver.Valuer); ok { return true }
switch reflect.ValueOf(v).Kind() {
case reflect.Struct, reflect.Map, reflect.Chan, reflect.Func, reflect.Array:
return false
}
return true
} Try / catch
// Returned from Exec/Query for unsupported argument kinds.
if _, err := stmt.Exec(args...); err != nil {
if strings.Contains(err.Error(), "unsupported type") {
// pass a primitive field or implement driver.Valuer
}
} Prevention
- Pass scalar fields, not whole structs, to Exec.
- Implement driver.Valuer for types you routinely store.
- Add a guard rejecting struct/map/chan/func args.
When it happens
Trigger: Passing a struct, map, chan, func, or array as a prepared-statement argument - e.g. passing a model struct instead of one of its scalar fields.
Common situations: Accidentally passing a whole model/config struct; plumbing the wrong variable into Exec.
Related errors
- cannot convert type: %T
- non-Value type %T returned from Value
- unsupported type %T, a slice of
- argument count mismatch
- can't convert %T to time.Time
AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07).
Data as JSON: /api/errors/c7a5dee657dea184.
Report an issue: GitHub.
Appendix: 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 03d76c7e07)