laravel/framework · error · MultipleRecordsFoundException

$count records were found.

Error message

$count records were found.

What it means

MultipleRecordsFoundException (RuntimeException) from sole() when the query returns more than one row. sole() is meant to fetch exactly one record; it limits to 2 rows and throws if it gets 2, surfacing the count so callers know the query was not selective enough.

Solutions

  1. Add a uniqueness constraint/migration on the column you query by.
  2. Tighten the query with additional where conditions so only one row matches.
  3. If duplicates are expected, use first() instead of sole().
  4. Clean up duplicate rows and add a unique index to prevent recurrence.

Example fix

// before
$user = User::where('email', $email)->sole(); // >1 rows
// after
$user = User::where('email', $email)->sole(); // plus migration:
// Schema::table('users', fn ($t) => $t->unique('email'));
// or, if duplicates are acceptable:
$user = User::where('email', $email)->first();
Defensive patterns

Strategy: validation

Validate before calling

// Before sole(), assert the query yields exactly one row.
$count = Model::where('email', $email)->count();
if ($count !== 1) {
    throw new RuntimeException("Expected exactly 1 row for email [$email], found $count.");
}
$user = Model::where('email', $email)->sole();

Type guard

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

Try / catch

use Illuminate\Database\MultipleRecordsFoundException;
use Illuminate\Database\RecordsNotFoundException;

try {
    $user = Model::where('email', $email)->sole();
} catch (MultipleRecordsFoundException $e) {
    // deduplicate rows, tighten the query, or fall back to first()
} catch (RecordsNotFoundException $e) {
    abort(404);
}

Prevention

When it happens

Trigger: Model::where('email', $e)->sole() when duplicate emails exist; sole() on a query missing a uniqueness guarantee; lookup by a non-unique column expecting a single match.

Common situations: Data-integrity drift (duplicate rows that should be unique); soft-deletes causing two rows (one deleted, one live) when only live was expected; missing where clause; race insert creating a duplicate.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/b01aa82089049e03. Report an issue: GitHub.

Appendix: 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 e0f6eb3518)