laravel/framework · error · MultipleRecordsFoundException

{$count} records were found.

Error message

{$count} records were found.

What it means

Relation::sole() executes the relationship query expecting exactly one matching row. It runs with limit(2); if more than one row is returned it throws MultipleRecordsFoundException carrying the count. sole() is the strict counterpart to first() and is used when the developer asserts the relation matches a single record.

Source

Thrown at src/Illuminate/Database/Eloquent/Relations/Relation.php:271

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

        $count = $result->count();

        if ($count === 0) {
            throw (new ModelNotFoundException)->setModel(get_class($this->related));
        }

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

        return $result->first();
    }

    /**
     * Execute the query as a "select" statement.
     *
     * @param  array  $columns
     * @return \Illuminate\Database\Eloquent\Collection<int, TRelatedModel>
     */
    public function get($columns = ['*'])
    {
        return $this->query->get($columns);
    }

    /**
     * Touch all of the related models for the relationship.

View on GitHub (pinned to e0f6eb3518)

Solutions

  1. Tighten the query with where() so only one row can match before calling sole().
  2. Use first() or firstOrFail() if more than one row is acceptable.
  3. Catch \Illuminate\Database\MultipleRecordsFoundException and decide recovery (pick latest, error out, etc.).
  4. Fix the underlying data - deduplicate the rows that caused the ambiguity.

Example fix

// before
$latest = $user->orders()->sole(); // throws if user has >1 order

// after - constrain to exactly one
$latest = $user->orders()->latest()->sole();
// or accept the first
$any = $user->orders()->first();
Defensive patterns

Strategy: try-catch

Validate before calling

// If more than one row may match, do not use sole(). Constrain first.
// Optional pre-count guard:
$count = $model->relation()->count();
if ($count > 1) {
    throw new \RuntimeException('Relation matches multiple rows; tighten the query before sole().');
}
$model->relation()->sole();

Try / catch

try {
    $item = $user->orders()->sole();
} catch (\Illuminate\Database\MultipleRecordsFoundException $e) {
    // multiple matched - recover by picking latest, or surface error
    $item = $user->orders()->latest()->first();
}

Prevention

When it happens

Trigger: Calling $model->relation()->sole() or any query scope ending in sole() on a relation that matches 2+ rows. The message '{$count} records were found.' comes from MultipleRecordsFoundException.

Common situations: Assuming a hasMany/belongsToMany matches exactly one when the data has duplicates; using sole() in seeders/tests where duplicate fixtures exist; race conditions inserting a second row before sole() runs.

Related errors


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