{"id":"3a90ee9c263720ca","repo":"laravel/framework","slug":"the-number-of-columns-must-match-the-number-of-val","errorCode":null,"errorMessage":"The number of columns must match the number of values","messagePattern":"The number of columns must match the number of values","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Database/Query/Builder.php","lineNumber":2226,"sourceCode":"\n        return $this;\n    }\n\n    /**\n     * Adds a where condition using row values.\n     *\n     * @param  array  $columns\n     * @param  string  $operator\n     * @param  array  $values\n     * @param  string  $boolean\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function whereRowValues($columns, $operator, $values, $boolean = 'and')\n    {\n        if (count($columns) !== count($values)) {\n            throw new InvalidArgumentException('The number of columns must match the number of values');\n        }\n\n        $type = 'RowValues';\n\n        $this->wheres[] = ['type' => $type, 'columns' => $columns, 'operator' => $operator, 'values' => $values, 'boolean' => $boolean];\n\n        $this->addBinding($this->cleanBindings($values));\n\n        return $this;\n    }\n\n    /**\n     * Adds an or where condition using row values.\n     *\n     * @param  array  $columns\n     * @param  string  $operator\n     * @param  array  $values\n     * @return $this","sourceCodeStart":2208,"sourceCodeEnd":2244,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Database/Query/Builder.php#L2208-L2244","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\n$query->whereRowValues(['tenant_id','user_id'], '=', [$tenantId])->get();\n// => The number of columns must match the number of values\n\n// after\n$query->whereRowValues(['tenant_id','user_id'], '=', [$tenantId, $userId])->get();","handlingStrategy":"validation","validationCode":"if (count($columns) !== count($values)) {\n    throw new \\InvalidArgumentException('whereRowValues: columns ('.count($columns).') vs values ('.count($values).') mismatch.');\n}","typeGuard":"/** @param list<mixed> $columns @param list<mixed> $values */\nfunction sameArity(array $columns, array $values): bool\n{\n    return count($columns) === count($values);\n}","tryCatchPattern":"// Validate arity before the call; catching here is rarely useful because the\n// mismatch is a programming bug, not transient state.","preventionTips":["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."],"tags":["query-builder","row-values","arity-mismatch","invalid-argument"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}