go-sql-driver/mysql · error
cannot convert type: %T
Error message
cannot convert type: %T
What it means
Returned by writeExecutePacket's type switch (packets.go:1223) when a bound argument's concrete type is not one the driver can serialize: only int64, uint64, float64, bool, []byte, string, time.Time, and json.RawMessage are handled. Any other type reaching this default branch is rejected. Under database/sql the default converter normally normalizes types first, so hitting this means a non-normalized type reached the driver's execute path.
Source
Thrown at packets.go:1223
var a [64]byte
var b = a[:0]
if v.IsZero() {
b = append(b, "0000-00-00"...)
} else {
b, err = appendDateTime(b, v.In(mc.cfg.Loc), mc.cfg.timeTruncate)
if err != nil {
return err
}
}
paramValues = appendLengthEncodedInteger(paramValues,
uint64(len(b)),
)
paramValues = append(paramValues, b...)
default:
return fmt.Errorf("cannot convert type: %T", arg)
}
}
// Check if param values exceeded the available buffer
// In that case we must build the data packet with the new values buffer
if valuesCap != cap(paramValues) {
data = append(data[:pos], paramValues...)
mc.buf.store(data) // allow this buffer to be reused
}
pos += len(paramValues)
data = data[:pos]
}
err = mc.writePacket(data)
mc.syncSequence()
return err
}View on GitHub (pinned to c426bd9379)
Solutions
- Convert the value to a supported primitive (string, []byte, int64, time.Time) before binding.
- Implement driver.Valuer on the custom type so its Value() returns a base driver.Value.
- Marshal structs/maps to JSON and pass the resulting []byte.
Example fix
// before — passing a struct directly stmt.Exec(ctx, myStruct) // after — marshal to JSON b, _ := json.Marshal(myStruct) stmt.Exec(ctx, b)
Defensive patterns
Strategy: type-guard
Validate before calling
func toDriverValue(v any) (any, error) {
switch v.(type) {
case nil, int64, uint64, float64, bool, []byte, string, time.Time, json.RawMessage:
return v, nil
case driver.Valuer:
return v.(driver.Valuer).Value()
}
b, err := json.Marshal(v)
return b, err
} Type guard
func isBindable(v any) bool {
switch v.(type) {
case nil, int64, uint64, float64, bool, []byte, string, time.Time, json.RawMessage:
return true
}
return false
} Try / catch
if _, err := stmt.Exec(args...); err != nil {
if strings.Contains(err.Error(), "cannot convert type") {
// an arg has an unsupported type; convert it or implement driver.Valuer
}
} Prevention
- Implement driver.Valuer on custom types used as parameters.
- Marshal structs/maps to []byte before binding.
- Restrict parameter values to the supported primitive set.
When it happens
Trigger: Passing a struct, map, array, chan, or a custom type that does not implement driver.Valuer as a prepared-statement argument; a plain int/uint/float32 that was not narrowed to int64/uint64/float64 at the driver boundary.
Common situations: Custom types lacking a driver.Valuer implementation; expecting the driver to auto-serialize a struct to JSON; passing an unhandled numeric width.
Related errors
- argument count mismatch (got: %d; has: %d)
- non-Value type %T returned from Value
- unsupported type %T, a slice of %s
- unsupported type %T, a %s
- invalid DATETIME packet length %d
AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04).
Data as JSON: /data/errors/933fd9db908a34ea.json.
Report an issue: GitHub.