laravel/framework · error · InvalidArgumentException
The unique columns must not be empty.
Error message
The unique columns must not be empty.
What it means
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.
Source
Thrown at src/Illuminate/Database/Query/Builder.php:4213
$this->cleanBindings(Arr::flatten($values, 1))
);
}
/**
* Insert new records into the database and returning specified columns with optional ignoring specific conflicts.
*
* @param non-empty-array<non-empty-string> $returning
* @param non-empty-string|non-empty-array<non-empty-string>|null $uniqueBy
* @return \Illuminate\Support\Collection
*/
public function insertOrIgnoreReturning(array $values, array $returning = ['*'], array|string|null $uniqueBy = null)
{
if (empty($values)) {
return new Collection;
}
if ($uniqueBy === [] || $uniqueBy === '') {
throw new InvalidArgumentException('The unique columns must not be empty.');
}
if ($returning === []) {
throw new InvalidArgumentException('The returning columns must not be empty.');
}
if (! is_array(array_first($values))) {
$values = [$values];
} else {
foreach ($values as $key => $value) {
ksort($value);
$values[$key] = $value;
}
}
$this->applyBeforeQueryCallbacks();
View on GitHub (pinned to bd6b5437e6)
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.
Example fix
// before
DB::table('users')->insertOrIgnoreReturning($rows, ['*'], []);
// => The unique columns must not be empty.
// after
DB::table('users')->insertOrIgnoreReturning($rows, ['*'], ['email']); Defensive patterns
Strategy: validation
Validate before calling
$uniqueBy = array_filter(array_map('strval', (array) $uniqueBy));
if ($uniqueBy === [] ) {
throw new \InvalidArgumentException('insertOrIgnoreReturning requires a non-empty $uniqueBy.');
}
$table->insertOrIgnoreReturning($values, ['*'], $uniqueBy); Type guard
/** @param non-empty-string|non-empty-array<int,non-empty-string>|null $u */
function isValidUniqueBy(array|string|null $u): bool
{
if (is_string($u)) { return $u !== ''; }
if (is_array($u)) { return $u !== [] && array_all($u, fn($v) => is_string($v) && $v !== ''); }
return false; // null is NOT valid here (target is mandatory)
} Try / catch
// Validate $uniqueBy before the call; catching here is low value.
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- The returning columns must not be empty.
- A subquery must be a query builder instance, a Closure, or a
- Nested arrays may not be passed to whereIn method.
- The number of columns must match the number of values
- Order direction must be a SortDirection, "asc" or "desc".
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/113ebafef388e640.json.
Report an issue: GitHub.