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
- Add a uniqueness constraint/migration on the column you query by.
- Tighten the query with additional where conditions so only one row matches.
- If duplicates are expected, use first() instead of sole().
- 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
- Enforce uniqueness with a DB unique index on columns used with sole().
- Add where conditions sufficient to guarantee a single match.
- Reserve sole() for invariants you expect the schema to guarantee.
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
- No record found for the given query.
- A subquery must be a query builder instance, a Closure, or…
- Collection given to whereAttachedTo method may not be empty.
- Collection given to whereBelongsTo method may not be empty.
- Collection given to whereMorphedTo method may not be empty.
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)