{"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/c426bd93799de0f0e094c8f0582872c529d0ed0a/packets.go#L1205-L1241","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom types lacking a driver.Valuer implementation; expecting the driver to auto-serialize a struct to JSON; passing an unhandled numeric width.","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."],"exampleFix":"// before — passing a struct directly\nstmt.Exec(ctx, myStruct)\n\n// after — marshal to JSON\nb, _ := json.Marshal(myStruct)\nstmt.Exec(ctx, b)","handlingStrategy":"type-guard","validationCode":"func toDriverValue(v any) (any, error) {\n    switch v.(type) {\n    case nil, int64, uint64, float64, bool, []byte, string, time.Time, json.RawMessage:\n        return v, nil\n    case driver.Valuer:\n        return v.(driver.Valuer).Value()\n    }\n    b, err := json.Marshal(v)\n    return b, err\n}","typeGuard":"func isBindable(v any) bool {\n    switch v.(type) {\n    case nil, int64, uint64, float64, bool, []byte, string, time.Time, json.RawMessage:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if _, err := stmt.Exec(args...); err != nil {\n    if strings.Contains(err.Error(), \"cannot convert type\") {\n        // an arg has an unsupported type; convert it or implement driver.Valuer\n    }\n}","preventionTips":["Implement driver.Valuer on custom types used as parameters.","Marshal structs/maps to []byte before binding.","Restrict parameter values to the supported primitive set."],"tags":["types","prepared-statement","serialization","api-misuse"],"analyzedSha":"c426bd93799de0f0e094c8f0582872c529d0ed0a","analyzedAt":"2026-08-04T21:52:59.219Z","schemaVersion":2}