go-sql-driver/mysql · error

cannot convert type: %T

Error message

cannot convert type: %T

What it means

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.

Source

Thrown at packets.go:1223

				var a [64]byte
				var b = a[:0]

				if v.IsZero() {
					b = append(b, "0000-00-00"...)
				} else {
					b, err = appendDateTime(b, v.In(mc.cfg.Loc), mc.cfg.timeTruncate)
					if err != nil {
						return err
					}
				}

				paramValues = appendLengthEncodedInteger(paramValues,
					uint64(len(b)),
				)
				paramValues = append(paramValues, b...)

			default:
				return fmt.Errorf("cannot convert type: %T", arg)
			}
		}

		// Check if param values exceeded the available buffer
		// In that case we must build the data packet with the new values buffer
		if valuesCap != cap(paramValues) {
			data = append(data[:pos], paramValues...)
			mc.buf.store(data) // allow this buffer to be reused
		}

		pos += len(paramValues)
		data = data[:pos]
	}

	err = mc.writePacket(data)
	mc.syncSequence()
	return err
}

View on GitHub (pinned to c426bd9379)

Solutions

  1. Convert the value to a supported primitive (string, []byte, int64, time.Time) before binding.
  2. Implement driver.Valuer on the custom type so its Value() returns a base driver.Value.
  3. Marshal structs/maps to JSON and pass the resulting []byte.

Example fix

// before — passing a struct directly
stmt.Exec(ctx, myStruct)

// after — marshal to JSON
b, _ := json.Marshal(myStruct)
stmt.Exec(ctx, b)
Defensive patterns

Strategy: type-guard

Validate before calling

func toDriverValue(v any) (any, error) {
    switch v.(type) {
    case nil, int64, uint64, float64, bool, []byte, string, time.Time, json.RawMessage:
        return v, nil
    case driver.Valuer:
        return v.(driver.Valuer).Value()
    }
    b, err := json.Marshal(v)
    return b, err
}

Type guard

func isBindable(v any) bool {
    switch v.(type) {
    case nil, int64, uint64, float64, bool, []byte, string, time.Time, json.RawMessage:
        return true
    }
    return false
}

Try / catch

if _, err := stmt.Exec(args...); err != nil {
    if strings.Contains(err.Error(), "cannot convert type") {
        // an arg has an unsupported type; convert it or implement driver.Valuer
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: Custom types lacking a driver.Valuer implementation; expecting the driver to auto-serialize a struct to JSON; passing an unhandled numeric width.

Related errors


AI-assisted analysis of go-sql-driver/mysql@c426bd9379 (2026-08-04). Data as JSON: /data/errors/933fd9db908a34ea.json. Report an issue: GitHub.