jmoiron/sqlx · error

number of bindVars less than number arguments

Error message

number of bindVars less than number arguments

What it means

After walking the query and consuming bind vars for each argument, sqlx.In() checks whether any arguments remain unused. If so, the query has fewer '?' placeholders than arguments, so the leftover arguments cannot be bound and this error is returned.

Source

Thrown at bind.go:240

		// write everything up to and including our ? character
		buf.WriteString(query[:offset+i+1])

		for si := 1; si < argMeta.length; si++ {
			buf.WriteString(", ?")
		}

		newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)

		// slice the query and reset the offset. this avoids some bookkeeping for
		// the write after the loop
		query = query[offset+i+1:]
		offset = 0
	}

	buf.WriteString(query)

	if arg < len(meta) {
		return "", nil, errors.New("number of bindVars less than number arguments")
	}

	return buf.String(), newArgs, nil
}

func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {
	switch val := v.Interface().(type) {
	case []interface{}:
		args = append(args, val...)
	case []int:
		for i := range val {
			args = append(args, val[i])
		}
	case []string:
		for i := range val {
			args = append(args, val[i])
		}
	default:

View on GitHub (pinned to 41dac167fd)

Solutions

  1. Remove unused arguments or add the missing '?' placeholders
  2. Make the IN expansion explicit: each slice arg needs its own '?' in the query
  3. Generate the WHERE clause programmatically so placeholders and args stay in sync
  4. Switch to NamedQuery with a struct/map so argument wiring is by name

Example fix

// before
query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?)", ids, status)
// after
query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?) AND status=?", ids, status)
Defensive patterns

Strategy: validation

Validate before calling

placeholders := strings.Count(query, "?")
if placeholders != len(args) {
    return "", nil, fmt.Errorf("expected %d args, got %d", placeholders, len(args))
}
q, a, err := sqlx.In(query, args...)

Try / catch

query, args, err := sqlx.In(q, args...)
if err != nil {
    if strings.Contains(err.Error(), "less than number arguments") {
        log.Printf("dropped args for query %s: got %d", q, len(args))
    }
    return err
}

Prevention

When it happens

Trigger: Calling sqlx.In with more arguments than '?' placeholders in the query, e.g. sqlx.In("SELECT * FROM t WHERE a=?", a, b) — after binding, arg < len(meta).

Common situations: Appending optional conditions in code without updating the query string; passing extra args after refactoring; building dynamic SQL where a condition was dropped but its argument kept.

Related errors


AI-assisted analysis of jmoiron/sqlx@41dac167fd (2026-09-03). Data as JSON: /api/errors/f170efc75f329060. Report an issue: GitHub.