laravel/framework · error · MultipleItemsFoundException

$count items were found.

Error message

$count items were found.

What it means

Thrown by Collection::sole() (via MultipleItemsFoundException) when more than one item matches the criteria. sole() asserts exactly one match and returns it, mirroring the database sole()/firstOrFail() pattern. The message includes the actual matched count so you can see how many duplicates exist. ItemNotFoundException is the counterpart for zero matches.

Source

Thrown at src/Illuminate/Collections/Collection.php:1460

     * @throws \Illuminate\Support\ItemNotFoundException
     * @throws \Illuminate\Support\MultipleItemsFoundException
     */
    public function sole($key = null, $operator = null, $value = null)
    {
        $filter = func_num_args() > 1
            ? $this->operatorForWhere(...func_get_args())
            : $key;

        $items = $this->unless($filter == null)->filter($filter);

        $count = $items->count();

        if ($count === 0) {
            throw new ItemNotFoundException;
        }

        if ($count > 1) {
            throw new MultipleItemsFoundException($count);
        }

        return $items->first();
    }

    /**
     * Determine if the collection contains a single item, optionally matching the given criteria.
     *
     * @param  (callable(TValue, TKey): bool)|string|null  $key
     * @param  mixed  $operator
     * @param  mixed  $value
     * @return bool
     */
    public function hasSole($key = null, $operator = null, $value = null): bool
    {
        $filter = func_num_args() > 1
            ? $this->operatorForWhere(...func_get_args())
            : $key;

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Ensure the matching criteria is actually unique; add a unique DB index/constraint on the field.
  2. Use first() instead of sole() if multiple matches are acceptable.
  3. Use sole() only after a unique-scoped query, or pre-filter to guarantee uniqueness.

Example fix

// before
$user = User::all()->sole(fn ($u) => $u->email === $email);

// after
$user = User::whereEmail($email)->sole(); // DB-level unique, no dup risk
Defensive patterns

Strategy: try-catch

Validate before calling

$matches = $collection->filter($criteria);
abort_if($matches->count() > 1, 409, 'Duplicate record');
$item = $matches->first();

Try / catch

try {
    $item = $collection->sole('email', $email);
} catch (\Illuminate\Support\MultipleItemsFoundException $e) {
    // log and pick deterministic first, or surface conflict
    $item = $collection->where('email', $email)->first();
} catch (\Illuminate\Support\ItemNotFoundException $e) {
    $item = null;
}

Prevention

When it happens

Trigger: Calling $collection->sole() on a collection with 2+ items, or $collection->sole('status', 'active') when multiple items have status=active. Also sole(fn($u) => $u->role === 'admin') with several admins.

Common situations: Querying for a unique record (by email, token, slug) but the data has duplicates due to a missing unique constraint. Test fixtures seeding multiple matching rows. Lookup-by-unique-field assumptions that break when data integrity slips.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/8e60bba5192f5419.json. Report an issue: GitHub.