laravel/framework · error · InvalidArgumentException
Nested arrays may not be passed to whereIn method.
Error message
Nested arrays may not be passed to whereIn method.
What it means
whereIn() stores its values array as bindings, and the grammar flattens exactly one level. After pushing the values into $this->wheres, the builder verifies count($values) === count(Arr::flatten($values, 1)); a mismatch means a nested array was passed, which would silently corrupt bindings or emit wrong SQL, so it throws InvalidArgumentException.
Solutions
- Flatten or map your input to a flat list of scalars before passing: ->whereIn('id', $rows->pluck('id')->all()).
- For multi-column tuple matching use whereIn with an array of arrays via whereIn('col', $query) subquery form, or use whereRowValues per row.
- Switch to whereJsonContains if you actually need array-membership semantics on a JSON column.
Example fix
// before
->whereIn('user_id', $orders->map(fn ($o) => $o->user_ids)) // user_ids is an array
// after
->whereIn('user_id', $orders->flatMap(fn ($o) => $o->user_ids)) Defensive patterns
Strategy: validation
Validate before calling
if (Arr::isList($values) && count($values) === count(Arr::flatten($values, 1))) {
// safe: flat list of scalars
}
$values = array_values(Arr::flatten($values, 1)); // force-flatten to a scalar list
$query->whereIn('id', $values); Type guard
function isFlatScalarList(array $values): bool
{
if (count($values) !== count(\Illuminate\Support\Arr::flatten($values, 1))) {
return false;
}
foreach ($values as $v) {
if (is_array($v) || is_object($v) && ! ($v instanceof \Illuminate\Contracts\Database\Query\Expression)) {
return false;
}
}
return true;
} Prevention
- Map collections down to a single scalar column with ->pluck('col')->all() before whereIn().
- Avoid multi-column tuples in whereIn; use whereRowValues or whereJsonContains instead.
- Add a test that asserts whereIn input is flat when building queries dynamically.
When it happens
Trigger: ->whereIn('id', [[1, 2], [3, 4]]), ->whereIn('role', $collectionOfArrays), or any case where an element of $values is itself an array (after Arrayable casting).
Common situations: Pluck()ing two columns and forgetting to extract one ('->pluck(['a','b'])'); groupBy + pluck returning nested structure; passing an Eloquent collection of models instead of an array of scalars; multi-column tuples mistakenly passed to whereIn.
Related errors
- A subquery must be a query builder instance, a Closure, or…
- Non-numeric value passed as decrement amount for column…
- Non-numeric value passed as increment amount for column…
- Non-numeric value passed to decrement method.
- Non-numeric value passed to increment method.
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/8dc54a35e6cc07ac.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Database/Query/Builder.php:1447
if ($this->isQueryable($values)) {
[$query, $bindings] = $this->createSub($values);
$values = [new Expression($query)];
$this->addBinding($bindings, 'where');
}
// Next, if the value is Arrayable we need to cast it to its raw array form so we
// have the underlying array value instead of an Arrayable object which is not
// able to be added as a binding, etc. We will then add to the wheres array.
if ($values instanceof Arrayable) {
$values = $values->toArray();
}
$this->wheres[] = ['type' => $type, 'column' => $column, 'values' => $values, 'boolean' => $boolean];
if (count($values) !== count(Arr::flatten($values, 1))) {
throw new InvalidArgumentException('Nested arrays may not be passed to whereIn method.');
}
// Finally, we'll add a binding for each value unless that value is an expression
// in which case we will just skip over it since it will be the query as a raw
// string and not as a parameterized place-holder to be replaced by the PDO.
$this->addBinding($this->cleanBindings($values), 'where');
return $this;
}
/**
* Add an "or where in" clause to the query.
*
* @param \Illuminate\Contracts\Database\Query\Expression|string $column
* @param mixed $values
* @return $this
*/
public function orWhereIn($column, $values)View on GitHub (pinned to e0f6eb3518)