laravel/framework · error · RecordNotFoundException

No record found for the given query.

Error message

No record found for the given query.

What it means

Thrown by Builder::firstOrFail when the query returns no rows. Unlike first() (which returns null), firstOrFail is the explicit 'I expect exactly one row' API and raises RecordNotFoundException (a subclass of RuntimeException's ModelNotFoundException family) so callers can distinguish 'not found' from null. The message defaults to 'No record found for the given query.' but can be customised via the second argument.

Source

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

        return $this->limit(1)->get($columns)->first();
    }

    /**
     * Execute the query and get the first result or throw an exception.
     *
     * @param  array|string  $columns
     * @param  string|null  $message
     * @return TValue
     *
     * @throws \Illuminate\Database\RecordNotFoundException
     */
    public function firstOrFail($columns = ['*'], $message = null)
    {
        if (! is_null($result = $this->first($columns))) {
            return $result;
        }

        throw new RecordNotFoundException($message ?: 'No record found for the given query.');
    }

    /**
     * Execute the query and get the first result if it's the sole matching record.
     *
     * @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) {

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Use first() if 'not found' is a valid business outcome and handle null explicitly.
  2. Catch Illuminate\Database\RecordNotFoundException (or ModelNotFoundException) to render a 404.
  3. Verify filters/scopes: check soft-deletes (use withTrashed()), tenant scope, and active scopes.
  4. Provide a clearer message: ->firstOrFail(['*'], 'User not found for email '.$email).

Example fix

// before
$user = User::where('email', $email)->firstOrFail();
// throws generic message

// after
use Illuminate\Database\RecordNotFoundException;

try {
    $user = User::where('email', $email)->firstOrFail(['*'], 'No user with that email.');
} catch (RecordNotFoundException $e) {
    abort(404, $e->getMessage());
}
Defensive patterns

Strategy: try-catch

Validate before calling

$row = Model::where('email', $email)->first();
if ($row === null) {
    abort(404, 'Not found');
}

Type guard

function rowExists(\Illuminate\Database\Eloquent\Builder $q): bool { return $q->exists(); }

Try / catch

use Illuminate\Database\RecordNotFoundException;
try {
    $user = User::where('email', $email)->firstOrFail();
} catch (RecordNotFoundException $e) {
    abort(404, $e->getMessage());
}

Prevention

When it happens

Trigger: User::where('email', $email)->firstOrFail() where no user has that email; route-model binding that falls through to firstOrFail; findOrFail equivalent via firstOrFail; using firstOrFail in a controller to enforce existence.

Common situations: Lookup by unique field where the value is missing; deleted/archived records filtered out by a global scope; wrong tenant/scope scoping the query to nothing; user-supplied ID that does not exist; soft-deletes hiding the row.

Related errors


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