jmoiron/sqlx · error
empty slice passed to 'in' query
Error message
empty slice passed to 'in' query
What it means
sqlx.In() builds an 'IN (...)' query by expanding slice arguments into a list of bind vars. If any passed argument is a slice with zero elements, there are no placeholders to expand and the generated SQL would be syntactically invalid, so sqlx refuses to build the query with this error.
Source
Thrown at bind.go:180
for i, arg := range args {
if a, ok := arg.(driver.Valuer); ok {
var err error
arg, err = a.Value()
if err != nil {
return "", nil, err
}
}
if v, ok := asSliceForIn(arg); ok {
meta[i].length = v.Len()
meta[i].v = v
anySlices = true
flatArgsCount += meta[i].length
if meta[i].length == 0 {
return "", nil, errors.New("empty slice passed to 'in' query")
}
} else {
meta[i].i = arg
flatArgsCount++
}
}
// don't do any parsing if there aren't any slices; note that this means
// 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)
View on GitHub (pinned to 41dac167fd)
Solutions
- Short-circuit before calling In: if len(slice)==0, skip the query or return an empty result set
- Construct the query differently for the empty case (e.g. query with a guaranteed-false predicate like "WHERE 1=0")
- Drop the IN clause entirely when the slice is empty
- Use Go's slices/len validation in a helper wrapper around sqlx.In
Example fix
// before
query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?)", ids)
// after
if len(ids) == 0 {
return nil, nil // or "SELECT * FROM users WHERE 1=0"
}
query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?)", ids) Defensive patterns
Strategy: validation
Validate before calling
func safeIn(query string, args ...interface{}) (string, []interface{}, error) {
for _, a := range args {
if rv := reflect.ValueOf(a); rv.Kind() == reflect.Slice && rv.Len() == 0 {
return "", nil, fmt.Errorf("empty slice for query %q", query)
}
}
return sqlx.In(query, args...)
} Type guard
func isEmptySliceArg(a interface{}) bool {
if a == nil { return false }
v := reflect.ValueOf(a)
return v.Kind() == reflect.Slice && v.Len() == 0
} Try / catch
query, args, err := sqlx.In("SELECT * FROM t WHERE id IN (?)", ids)
if err != nil {
if strings.Contains(err.Error(), "empty slice passed to 'in' query") {
return nil, nil // empty result is a valid outcome
}
return nil, err
} Prevention
- Always check len(slice) before building IN queries
- Route IN-query construction through a wrapper that handles the empty case
- Return empty results instead of querying when the filter list is empty
When it happens
Trigger: Calling sqlx.In (or QueryInx/NamedQuery variants that route through it) with an empty slice among the variadic args, e.g. sqlx.In("SELECT * FROM t WHERE id IN (?)", ids) where len(ids)==0. The check fires in the bind.go meta-building loop when meta[i].length==0.
Common situations: Filtering by a user-selected list that turned out empty (no checkboxes selected, no results from a previous query feeding an IN clause). Very common in list/filter endpoints where the filter collection starts empty.
Related errors
- number of bindVars exceeds arguments
- number of bindVars less than number arguments
- 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/4a9b08324a2f15f0.
Report an issue: GitHub.