laravel/framework · error · InvalidArgumentException
The number of columns must match the number of values
Error message
The number of columns must match the number of values
What it means
Thrown by whereRowValues when count($columns) !== count($values). whereRowValues builds a row-value constructor comparison `(col1, col2) = (v1, v2)` which SQL requires to have equal arity on both sides. Mismatched lengths would generate invalid SQL or silently misalign bindings.
Source
Thrown at src/Illuminate/Database/Query/Builder.php:2226
return $this;
}
/**
* Adds a where condition using row values.
*
* @param array $columns
* @param string $operator
* @param array $values
* @param string $boolean
* @return $this
*
* @throws \InvalidArgumentException
*/
public function whereRowValues($columns, $operator, $values, $boolean = 'and')
{
if (count($columns) !== count($values)) {
throw new InvalidArgumentException('The number of columns must match the number of values');
}
$type = 'RowValues';
$this->wheres[] = ['type' => $type, 'columns' => $columns, 'operator' => $operator, 'values' => $values, 'boolean' => $boolean];
$this->addBinding($this->cleanBindings($values));
return $this;
}
/**
* Adds an or where condition using row values.
*
* @param array $columns
* @param string $operator
* @param array $values
* @return $thisView on GitHub (pinned to bd6b5437e6)
Solutions
- Align the arrays: ensure count($columns) === count($values) by adding the missing column or removing the extra value.
- Build both sides from the same source: `whereRowValues(array_keys($row), '=', array_values($row))`.
- Add an assertion/guard before calling: `if (count($cols) !== count($vals)) throw ...`.
- Prefer multiple where clauses if you do not actually need row-tuple semantics.
Example fix
// before $query->whereRowValues(['tenant_id','user_id'], '=', [$tenantId])->get(); // => The number of columns must match the number of values // after $query->whereRowValues(['tenant_id','user_id'], '=', [$tenantId, $userId])->get();
Defensive patterns
Strategy: validation
Validate before calling
if (count($columns) !== count($values)) {
throw new \InvalidArgumentException('whereRowValues: columns ('.count($columns).') vs values ('.count($values).') mismatch.');
} Type guard
/** @param list<mixed> $columns @param list<mixed> $values */
function sameArity(array $columns, array $values): bool
{
return count($columns) === count($values);
} Try / catch
// Validate arity before the call; catching here is rarely useful because the // mismatch is a programming bug, not transient state.
Prevention
- Build both tuples from the same associative source: array_keys() and array_values().
- Add an assert() at the boundary of composite-key code.
- Use PHPStan generics on tuple params to surface arity drift.
When it happens
Trigger: `whereRowValues(['a','b'], '=', [1])`. Building composite keys where one side is built dynamically and the other statically. Selecting 3 columns but only providing 2 values from a composite unique key lookup.
Common situations: Composite primary key lookups with `(c1,c2,c3) = (?,?)`; polymorphic row comparisons where one tuple is computed and the other hand-coded; refactoring that adds a column on one side but not the other.
Related errors
- A subquery must be a query builder instance, a Closure, or a
- Nested arrays may not be passed to whereIn method.
- Order direction must be a SortDirection, "asc" or "desc".
- Timeout must be greater than zero.
- The unique columns must not be empty.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/3a90ee9c263720ca.json.
Report an issue: GitHub.