go-sql-driver/mysql · error

argument count mismatch (got: %d; has: %d)

Error message

argument count mismatch (got: %d; has: %d)

What it means

Returned by writeExecutePacket (packets.go:1047) when the number of arguments supplied to a prepared statement's Exec/Query does not equal stmt.paramCount, the number of '?' placeholders declared when the statement was prepared. The MySQL binary execute protocol requires an exact one-to-one mapping of arguments to placeholders.

Source

Thrown at packets.go:1047

		// Send CMD packet
		err := stmt.mc.writePacket(data[:4+pktLen])
		// Every COM_LONG_DATA packet reset Packet Sequence
		stmt.mc.resetSequence()
		if err == nil {
			data = data[pktLen-dataOffset:]
			continue
		}
		return err
	}

	return nil
}

// Execute Prepared Statement
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html
func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
	if len(args) != stmt.paramCount {
		return fmt.Errorf(
			"argument count mismatch (got: %d; has: %d)",
			len(args),
			stmt.paramCount,
		)
	}

	const minPktLen = 4 + 1 + 4 + 1 + 4
	mc := stmt.mc

	// Determine threshold dynamically to avoid packet size shortage.
	longDataSize := max(mc.maxAllowedPacket/(stmt.paramCount+1), 64)

	// Reset packet-sequence
	mc.resetSequence()

	var data []byte
	var err error

View on GitHub (pinned to c426bd9379)

Solutions

  1. Count the '?' placeholders in the prepared SQL and pass exactly that many arguments.
  2. Construct the argument slice from a structured source and assert its length matches the placeholder count.
  3. Add a unit test that verifies len(args) equals the expected placeholder count for each statement.

Example fix

// before — 2 placeholders, 3 args
stmt.Exec(ctx, "a", "b", "c")  // SQL: INSERT INTO t(x,y) VALUES(?,?)

// after
stmt.Exec(ctx, "a", "b")
Defensive patterns

Strategy: validation

Validate before calling

expected := strings.Count(sqlText, "?") // adjust for literal '?' as needed
if len(args) != expected {
    return fmt.Errorf("expected %d arguments, got %d", expected, len(args))
}

Try / catch

if _, err := stmt.Exec(args...); err != nil {
    if strings.Contains(err.Error(), "argument count mismatch") {
        // reconcile the number of '?' placeholders with the argument count
    }
}

Prevention

When it happens

Trigger: Calling stmt.Exec(a, b, c) on a statement prepared from SQL containing only two placeholders; building an argument slice dynamically and getting its length wrong; passing fewer args than placeholders.

Common situations: Adding or removing a '?' in the SQL without updating the argument list; an off-by-one when constructing a variadic args slice; copy-paste reuse of a statement with a different parameter count.

Related errors


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