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

  1. Return a standard driver.Value from Value(): use int64 for integers, string/[]byte/time.Time for the rest.
  2. Cast explicitly, e.g. return int64(m.Cents), not the raw int.
  3. 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

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


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(), nil

View on GitHub (pinned to 03d76c7e07)