jmoiron/sqlx · error
number of bindVars exceeds arguments
Error message
number of bindVars exceeds arguments
What it means
sqlx.In() walks the query string looking for '?' bind vars and expands each one using the corresponding argument. If the query contains more '?' placeholders than arguments were passed, the excess placeholders cannot be filled and this programmer error is reported (unlike database/sql, sqlx catches this eagerly at bind time).
Source
Thrown at bind.go:207
// some errors that we might have caught below will not be returned.
if !anySlices {
return query, args, nil
}
newArgs := make([]interface{}, 0, flatArgsCount)
var buf strings.Builder
buf.Grow(len(query) + len(", ?")*flatArgsCount)
var arg, offset int
for i := strings.IndexByte(query[offset:], '?'); i != -1; i = strings.IndexByte(query[offset:], '?') {
if arg >= len(meta) {
// if an argument wasn't passed, lets return an error; this is
// not actually how database/sql Exec/Query works, but since we are
// creating an argument list programmatically, we want to be able
// to catch these programmer errors earlier.
return "", nil, errors.New("number of bindVars exceeds arguments")
}
argMeta := meta[arg]
arg++
// not a slice, continue.
// our questionmark will either be written before the next expansion
// of a slice or after the loop when writing the rest of the query
if argMeta.length == 0 {
offset = offset + i + 1
newArgs = append(newArgs, argMeta.i)
continue
}
// write everything up to and including our ? character
buf.WriteString(query[:offset+i+1])
for si := 1; si < argMeta.length; si++ {View on GitHub (pinned to 41dac167fd)
Solutions
- Count '?' placeholders in the query and make sure each has exactly one argument
- Remove the extra '?' or add the missing argument
- Prefer named parameters via NamedQuery/PrepareNamed to avoid positional mismatches
- Note '?' inside quoted string literals are still counted — escape or remove them
Example fix
// before
query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?) AND status=?", ids)
// after
query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?) AND status=?", ids, status) Defensive patterns
Strategy: validation
Validate before calling
if strings.Count(query, "?") != len(args) {
return "", nil, fmt.Errorf("query has %d placeholders but %d args", strings.Count(query, "?"), 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(), "number of bindVars exceeds arguments") {
log.Printf("placeholder/arg mismatch in query: %s", q)
}
return err
} Prevention
- Count '?' in the query string and match against args before calling In
- Keep query text and argument construction adjacent in code
- Add unit tests that exercise every query-building path
- Remember '?' inside string literals still counts as a placeholder
When it happens
Trigger: Calling sqlx.In/QueryInx with a query string containing more '?' characters than variadic arguments, e.g. sqlx.In("SELECT * FROM t WHERE a=? AND b=?", valA) — the second '?' finds arg >= len(meta).
Common situations: Hand-edited queries where a condition was removed from the code but not the SQL string; typos producing stray '?' characters (including inside string literals); merging query fragments incorrectly.
Related errors
- number of bindVars less than number arguments
- empty slice passed to 'in' query
- unexpected `:` while reading named param at
- sql: RawBytes isn't allowed on Row.Scan
- must pass a pointer, not a value, to StructScan destination
AI-assisted analysis of jmoiron/sqlx@41dac167fd (2026-09-03).
Data as JSON: /api/errors/8d83bad05bb8fc89.
Report an issue: GitHub.