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.
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
- must pass a pointer, not a value, to StructScan destination
- nil pointer passed to StructScan destination
- non-statement type passed to Stmtx
AI-assisted analysis of jmoiron/sqlx@41dac167fd (2026-09-03).
Data as JSON: /api/errors/4a9b08324a2f15f0.
Report an issue: GitHub.
Appendix: 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)