laravel/framework · error · MultipleRecordsFoundException

$count records were found.

Error message

$count records were found.

What it means

Thrown by Builder::sole() when the query returns more than one row. sole() asserts the result set is exactly one record and raises MultipleRecordsFoundException (carrying the $count) when the count exceeds 1, so callers can detect uniqueness violations instead of silently picking the first.

Source

Thrown at src/Illuminate/Database/Concerns/BuildsQueries.php:407

     *
     * @param  array|string  $columns
     * @return TValue
     *
     * @throws \Illuminate\Database\RecordsNotFoundException
     * @throws \Illuminate\Database\MultipleRecordsFoundException
     */
    public function sole($columns = ['*'])
    {
        $result = $this->limit(2)->get($columns);

        $count = $result->count();

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

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

        return $result->first();
    }

    /**
     * Paginate the given query using a cursor paginator.
     *
     * @param  int  $perPage
     * @param  array|string  $columns
     * @param  string  $cursorName
     * @param  \Illuminate\Pagination\Cursor|string|null  $cursor
     * @return \Illuminate\Contracts\Pagination\CursorPaginator
     */
    protected function paginateUsingCursor($perPage, $columns = ['*'], $cursorName = 'cursor', $cursor = null)
    {
        if (! $cursor instanceof Cursor) {
            $cursor = is_string($cursor)

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Add a unique database index/constraint on the column you query via sole().
  2. Use firstOrFail() if you only need one row and duplicates are tolerable.
  3. Catch Illuminate\Database\MultipleRecordsFoundException to handle the violation explicitly.
  4. Narrow the query (->latest()->sole() etc.) or deduplicate the data first.

Example fix

// before
$license = License::where('key', $key)->sole();
// throws when two rows share the key

// after
// 1. add unique index: $table->string('key')->unique();
// 2. handle gracefully:
use Illuminate\Database\MultipleRecordsFoundException;
try {
    $license = License::where('key', $key)->sole();
} catch (MultipleRecordsFoundException $e) {
    abort(409, 'Duplicate license key: '.$e->count.' found.');
}
Defensive patterns

Strategy: try-catch

Validate before calling

$count = Model::where('key', $key)->count();
if ($count > 1) {
    throw new \RuntimeException("{$count} duplicates found");
}

Type guard

function isUnique(\Illuminate\Database\Eloquent\Builder $q): bool { return $q->count() <= 1; }

Try / catch

use Illuminate\Database\MultipleRecordsFoundException;
try {
    $rec = Model::where('key', $key)->sole();
} catch (MultipleRecordsFoundException $e) {
    abort(409, "{$e->count} records found");
}

Prevention

When it happens

Trigger: User::where('email', $email)->sole() where the email column is not unique and two rows match; looking up by a field you believed unique; race condition inserting a duplicate between check and use.

Common situations: Missing unique index on a column queried via sole(); data migration that created duplicates; querying by a non-unique attribute (name, status) where multiple rows legitimately match; soft-deleted duplicates.

Related errors


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