{"record":{"id":"933fd9db908a34ea","repo":"go-sql-driver/mysql","slug":"cannot-convert-type-t","errorCode":null,"errorMessage":"cannot convert type: %T","messagePattern":"cannot convert type: %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packets.go","lineNumber":1223,"sourceCode":"\t\t\t\tvar a [64]byte\n\t\t\t\tvar b = a[:0]\n\n\t\t\t\tif v.IsZero() {\n\t\t\t\t\tb = append(b, \"0000-00-00\"...)\n\t\t\t\t} else {\n\t\t\t\t\tb, err = appendDateTime(b, v.In(mc.cfg.Loc), mc.cfg.timeTruncate)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tparamValues = appendLengthEncodedInteger(paramValues,\n\t\t\t\t\tuint64(len(b)),\n\t\t\t\t)\n\t\t\t\tparamValues = append(paramValues, b...)\n\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"cannot convert type: %T\", arg)\n\t\t\t}\n\t\t}\n\n\t\t// Check if param values exceeded the available buffer\n\t\t// In that case we must build the data packet with the new values buffer\n\t\tif valuesCap != cap(paramValues) {\n\t\t\tdata = append(data[:pos], paramValues...)\n\t\t\tmc.buf.store(data) // allow this buffer to be reused\n\t\t}\n\n\t\tpos += len(paramValues)\n\t\tdata = data[:pos]\n\t}\n\n\terr = mc.writePacket(data)\n\tmc.syncSequence()\n\treturn err\n}","sourceCodeStart":1205,"sourceCodeEnd":1241,"githubUrl":"https://github.com/go-sql-driver/mysql/blob/03d76c7e07908e255ce62d126d07ede3f2365d86/packets.go#L1205-L1241","documentation":"While encoding prepared-statement arguments for the MySQL binary protocol, writeExecutePacket handles only nil/int64/uint64/float64/bool/[]byte/string/time.Time/json.RawMessage. Any other dynamic type falls through to this default. Normally ConvertValue normalizes Go types first, so this fires when a value bypasses that normalization (custom CheckNamedValue, direct driver use, or a non-canonical driver.Value).","triggerScenarios":"A custom driver.Valuer or driver.NamedValueChecker returning an unusual type; calling the driver directly with a struct/map/raw int; a value that survives database/sql's conversion as a non-standard type.","commonSituations":"Custom wrapper types that aren't true driver.Value types; passing a domain struct instead of one of its fields.","solutions":["Ensure custom Valuers return a standard driver.Value (int64, string, []byte, time.Time, etc.).","Implement driver.Valuer to convert your type into a supported primitive.","Convert the value to a supported Go type before passing it to Exec."],"exampleFix":"// before\ntype Money struct{ Cents int64 }\n// Money not a Valuer -> \"cannot convert type: *Money\"\nstmt.Exec(Money{100})\n// after\nfunc (m Money) Value() (driver.Value, error) { return m.Cents, nil }\nstmt.Exec(Money{100})","handlingStrategy":"validation","validationCode":"// Confirm each arg is a type the wire encoder accepts before Exec.\nfunc wireEncodable(v any) bool {\n    switch v.(type) {\n    case nil, int64, uint64, float64, bool, []byte, string, time.Time:\n        return true\n    }\n    if _, ok := v.(driver.Valuer); ok { return true }\n    return false\n}","typeGuard":"func isDriverValue(v any) bool {\n    if v == nil { return true }\n    switch v.(type) {\n    case int64, float64, bool, []byte, string, time.Time:\n        return true\n    }\n    return false\n}","tryCatchPattern":"// Returned from Exec/Query; indicates a non-encodable argument type.\nif _, err := stmt.Exec(args...); err != nil {\n    if strings.Contains(err.Error(), \"cannot convert type\") {\n        // fix the offending arg's type\n    }\n}","preventionTips":["Make domain types implement driver.Valuer returning a primitive.","Avoid passing structs/maps to prepared statements directly.","Validate custom types' Value() return type in unit tests."],"tags":["go","mysql","prepared-statement","types","serialization"],"backgroundTag":null,"analyzedSha":"03d76c7e07908e255ce62d126d07ede3f2365d86","analyzedAt":"2026-08-07T10:39:17.340Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}