{"record":{"id":"64cbfbab1d8030f0","repo":"go-sql-driver/mysql","slug":"non-value-type-t-returned-from-value","errorCode":null,"errorMessage":"non-Value type %T returned from Value","messagePattern":"non-Value type %T returned from Value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"statement.go","lineNumber":180,"sourceCode":"\tif driver.IsValue(v) {\n\t\treturn v, nil\n\t}\n\n\tif vr, ok := v.(driver.Valuer); ok {\n\t\tsv, err := callValuerValue(vr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif driver.IsValue(sv) {\n\t\t\treturn sv, nil\n\t\t}\n\t\t// A value returned from the Valuer interface can be \"a type handled by\n\t\t// a database driver's NamedValueChecker interface\" so we should accept\n\t\t// uint64 here as well.\n\t\tif u, ok := sv.(uint64); ok {\n\t\t\treturn u, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"non-Value type %T returned from Value\", sv)\n\t}\n\trv := reflect.ValueOf(v)\n\tswitch rv.Kind() {\n\tcase reflect.Ptr:\n\t\t// indirect pointers\n\t\tif rv.IsNil() {\n\t\t\treturn nil, nil\n\t\t} else {\n\t\t\treturn c.ConvertValue(rv.Elem().Interface())\n\t\t}\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn rv.Int(), nil\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn rv.Uint(), nil\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn rv.Float(), nil\n\tcase reflect.Bool:\n\t\treturn rv.Bool(), nil","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/statement.go#L162-L198","documentation":"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.","triggerScenarios":"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.","commonSituations":"Implementing the Valuer interface but returning the wrong concrete Go type (a common mistake: returning int where int64 is required).","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."],"exampleFix":"// before\nfunc (m Money) Value() (driver.Value, error) { return m.Cents, nil } // m.Cents is int\n// after\nfunc (m Money) Value() (driver.Value, error) { return int64(m.Cents), nil }","handlingStrategy":"validation","validationCode":"// Assert a Valuer's result is a canonical driver.Value before use.\nif vr, ok := v.(driver.Valuer); ok {\n    sv, err := vr.Value()\n    if err != nil { return err }\n    if !driver.IsValue(sv) {\n        if _, isU64 := sv.(uint64); !isU64 {\n            return fmt.Errorf(\"Value() returned non-Value type %T\", sv)\n        }\n    }\n}","typeGuard":"func returnsDriverValue(v any) bool {\n    vr, ok := v.(driver.Valuer)\n    if !ok { return true }\n    sv, err := vr.Value()\n    if err != nil { return false }\n    return driver.IsValue(sv) || reflect.TypeOf(sv).Kind() == reflect.Uint64\n}","tryCatchPattern":"// Returned during Exec/Query argument conversion.\nif _, err := stmt.Exec(args...); err != nil {\n    if strings.Contains(err.Error(), \"non-Value type\") {\n        // fix the offending type's Value() return type\n    }\n}","preventionTips":["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()."],"tags":["go","mysql","types","valuer","prepared-statement"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}