go-sql-driver/mysql · error
non-Value type %T returned from Value
Error message
non-Value type %T returned from Value
What it means
ConvertValue calls a driver.Valuer's Value() method; the result must be a standard driver.Value (int64, float64, bool, []byte, string, time.Time, nil) or a uint64 this driver also accepts. If Value() returns anything else (e.g. a raw int, a struct), this error names the offending type.
Solutions
- Return a standard driver.Value from Value(): use int64 for integers, string/[]byte/time.Time for the rest.
- Cast explicitly, e.g. return int64(m.Cents), not the raw int.
- Unit-test that Value()'s result satisfies driver.IsValue.
Example fix
// before
func (m Money) Value() (driver.Value, error) { return m.Cents, nil } // m.Cents is int
// after
func (m Money) Value() (driver.Value, error) { return int64(m.Cents), nil } Defensive patterns
Strategy: validation
Validate before calling
// Assert a Valuer's result is a canonical driver.Value before use.
if vr, ok := v.(driver.Valuer); ok {
sv, err := vr.Value()
if err != nil { return err }
if !driver.IsValue(sv) {
if _, isU64 := sv.(uint64); !isU64 {
return fmt.Errorf("Value() returned non-Value type %T", sv)
}
}
} Type guard
func returnsDriverValue(v any) bool {
vr, ok := v.(driver.Valuer)
if !ok { return true }
sv, err := vr.Value()
if err != nil { return false }
return driver.IsValue(sv) || reflect.TypeOf(sv).Kind() == reflect.Uint64
} Try / catch
// Returned during Exec/Query argument conversion.
if _, err := stmt.Exec(args...); err != nil {
if strings.Contains(err.Error(), "non-Value type") {
// fix the offending type's Value() return type
}
} Prevention
- Always return int64 (not int) for integer Valuers.
- Validate Value()'s return with driver.IsValue in tests.
- Prefer returning primitives over custom types from Value().
When it happens
Trigger: A custom type implementing driver.Valuer whose Value() returns int instead of int64, or a struct/map/slice that is not a valid driver.Value.
Common situations: Implementing the Valuer interface but returning the wrong concrete Go type (a common mistake: returning int where int64 is required).
Related errors
- cannot convert type: %T
- unsupported type %T, a
- 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/64cbfbab1d8030f0.
Report an issue: GitHub.
Appendix: source
Thrown at statement.go:180
if driver.IsValue(v) {
return v, nil
}
if vr, ok := v.(driver.Valuer); ok {
sv, err := callValuerValue(vr)
if err != nil {
return nil, err
}
if driver.IsValue(sv) {
return sv, nil
}
// A value returned from the Valuer interface can be "a type handled by
// a database driver's NamedValueChecker interface" so we should accept
// uint64 here as well.
if u, ok := sv.(uint64); ok {
return u, nil
}
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
}
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Ptr:
// indirect pointers
if rv.IsNil() {
return nil, nil
} else {
return c.ConvertValue(rv.Elem().Interface())
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int(), nil
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(), nilView on GitHub (pinned to 03d76c7e07)