go-sql-driver/mysql · error

mysql: driver does not support the use of Named Parameters

Error message

mysql: driver does not support the use of Named Parameters

What it means

Returned by namedValueToValue (utils.go:785) when any driver.NamedValue passed to Exec/Query carries a non-empty Name. go-sql-driver only supports positional '?' placeholders; it does not implement named-parameter binding (tracked as issue #561). Called from QueryContext/ExecContext on both mysqlConn and mysqlStmt (connection.go:637,656,690,709).

Solutions

  1. Use positional '?' placeholders and pass args in the matching order.
  2. If you have a name->value map, expand it to an ordered slice yourself before calling the driver.
  3. Switch to a layer that rewrites named params to positional (some query builders do this), or pre-process the SQL.
  4. Do not use sql.Named with this driver.

Example fix

// before: named parameter -> error
rows, err := db.Query("SELECT * FROM t WHERE id=:id", sql.Named("id", 7))

// after: positional placeholder
rows, err := db.Query("SELECT * FROM t WHERE id=?", 7)
Defensive patterns

Strategy: validation

Validate before calling

// Reject named args up front and translate maps to positional slices.
func toPositional(query string, named map[string]any, order []string) (string, []any) {
    args := make([]any, len(order))
    for i, k := range order { args[i] = named[k] }
    return query, args // query must already use '?' placeholders
}

Type guard

func isNamedParamRejected(err error) bool {
    return err != nil && strings.Contains(err.Error(), "Named Parameters")
}

Try / catch

if isNamedParamRejected(err) {
    // rewrite to positional '?' + ordered args, then retry.
}

Prevention

When it happens

Trigger: Calling db.QueryContext/db.ExecContext (or stmt equivalents) with arguments built via sql.Named("name", value), or any []driver.NamedValue where param.Name != "".

Common situations: Porting code from a driver that supports @name/:name binds; using an ORM/query builder that emits sql.Named by default; mixing named-style calls into a MySQL codebase.


AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07). Data as JSON: /api/errors/51243cad227a1492. Report an issue: GitHub.

Appendix: source

Thrown at utils.go:785

func (ae *atomicError) Set(value error) {
	ae.value.Store(value)
}

// Value returns the current error value
func (ae *atomicError) Value() error {
	if v := ae.value.Load(); v != nil {
		// this will panic if the value doesn't implement the error interface
		return v.(error)
	}
	return nil
}

func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
	dargs := make([]driver.Value, len(named))
	for n, param := range named {
		if len(param.Name) > 0 {
			// TODO: support the use of Named Parameters #561
			return nil, errors.New("mysql: driver does not support the use of Named Parameters")
		}
		dargs[n] = param.Value
	}
	return dargs, nil
}

func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
	switch sql.IsolationLevel(level) {
	case sql.LevelRepeatableRead:
		return "REPEATABLE READ", nil
	case sql.LevelReadCommitted:
		return "READ COMMITTED", nil
	case sql.LevelReadUncommitted:
		return "READ UNCOMMITTED", nil
	case sql.LevelSerializable:
		return "SERIALIZABLE", nil
	default:
		return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)

View on GitHub (pinned to 03d76c7e07)