{"id":"113ebafef388e640","repo":"laravel/framework","slug":"the-unique-columns-must-not-be-empty","errorCode":null,"errorMessage":"The unique columns must not be empty.","messagePattern":"The unique columns must not be empty\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Database/Query/Builder.php","lineNumber":4213,"sourceCode":"            $this->cleanBindings(Arr::flatten($values, 1))\n        );\n    }\n\n    /**\n     * Insert new records into the database and returning specified columns with optional ignoring specific conflicts.\n     *\n     * @param  non-empty-array<non-empty-string>  $returning\n     * @param  non-empty-string|non-empty-array<non-empty-string>|null  $uniqueBy\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function insertOrIgnoreReturning(array $values, array $returning = ['*'], array|string|null $uniqueBy = null)\n    {\n        if (empty($values)) {\n            return new Collection;\n        }\n\n        if ($uniqueBy === [] || $uniqueBy === '') {\n            throw new InvalidArgumentException('The unique columns must not be empty.');\n        }\n\n        if ($returning === []) {\n            throw new InvalidArgumentException('The returning columns must not be empty.');\n        }\n\n        if (! is_array(array_first($values))) {\n            $values = [$values];\n        } else {\n            foreach ($values as $key => $value) {\n                ksort($value);\n\n                $values[$key] = $value;\n            }\n        }\n\n        $this->applyBeforeQueryCallbacks();\n","sourceCodeStart":4195,"sourceCodeEnd":4231,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Database/Query/Builder.php#L4195-L4231","documentation":"Thrown by insertOrIgnoreReturning when $uniqueBy is either an empty array `[]` or an empty string ''. The uniqueBy columns define the conflict target for the INSERT ... ON CONFLICT DO NOTHING (or equivalent) used by insertOrIgnoreReturning; an empty conflict target is invalid because the database cannot decide which rows to ignore without a key.","triggerScenarios":"Calling `insertOrIgnoreReturning($values, ['*'], [])` with an empty uniqueBy array. Passing `config('app.upsert_key', '')` when the config is unset. Building $uniqueBy from `array_keys($values)` after the values array was reduced to a single flat row.","commonSituations":"Generic repository helpers defaulting $uniqueBy to [] for flexibility; refactoring from upsert() (where uniqueBy is mandatory) to insertOrIgnoreReturning and forgetting to thread the key through; test code passing [] as a placeholder.","solutions":["Provide the conflict column(s): `insertOrIgnoreReturning($values, ['*'], 'email')` or `['tenant_id','email']`.","Ensure the column(s) have a unique index/constraint in the schema, otherwise the conflict clause is meaningless.","Validate before calling: `if (empty($uniqueBy)) throw new LogicException('uniqueBy required');`.","If no conflict target exists, use plain `insert()` or `insertOrIgnore()` instead."],"exampleFix":"// before\nDB::table('users')->insertOrIgnoreReturning($rows, ['*'], []);\n// => The unique columns must not be empty.\n\n// after\nDB::table('users')->insertOrIgnoreReturning($rows, ['*'], ['email']);","handlingStrategy":"validation","validationCode":"$uniqueBy = array_filter(array_map('strval', (array) $uniqueBy));\nif ($uniqueBy === [] ) {\n    throw new \\InvalidArgumentException('insertOrIgnoreReturning requires a non-empty $uniqueBy.');\n}\n$table->insertOrIgnoreReturning($values, ['*'], $uniqueBy);","typeGuard":"/** @param non-empty-string|non-empty-array<int,non-empty-string>|null $u */\nfunction isValidUniqueBy(array|string|null $u): bool\n{\n    if (is_string($u)) { return $u !== ''; }\n    if (is_array($u)) { return $u !== [] && array_all($u, fn($v) => is_string($v) && $v !== ''); }\n    return false; // null is NOT valid here (target is mandatory)\n}","tryCatchPattern":"// Validate $uniqueBy before the call; catching here is low value.","preventionTips":["Always specify the conflict column(s) explicitly in repository helpers.","Ensure a matching unique index exists in the migration.","Fall back to insertOrIgnore() when you do not need returned rows."],"tags":["query-builder","insert","upsert","invalid-argument"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}