cakephp/cakephp · error · RecordNotFoundException

Record not found in table

Error message

Record not found in table `%s`.

What it means

SelectQuery::firstOrFail() executes the query and throws Cake\Datasource\Exception\RecordNotFoundException when no row matches. The library throws it to give callers a fail-fast semantic for 'this record must exist'. The table name in the message comes from the query's repository via getTable().

Solutions

  1. Wrap the call in try/catch for RecordNotFoundException and handle the missing-record case (404 response, fallback)
  2. Verify the WHERE conditions and values actually match rows (log the SQL, run it manually)
  3. Check the row isn't excluded by a status/deleted scope on the query
  4. If empty results are legitimate, use first() instead of firstOrFail() and null-check

Example fix

// before
$article = $articles->find()->where(['slug' => $slug])->firstOrFail();
// after
try {
    $article = $articles->find()->where(['slug' => $slug])->firstOrFail();
} catch (RecordNotFoundException $e) {
    throw new NotFoundException(__("No article with slug {0}", $slug));
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before
$count = $query->count(); // or: $exists = $query->count() > 0;
if ($count === 0) { /* handle empty */ }

Type guard

$entity = $query->first();
if ($entity === null) { /* not found */ }

Try / catch

use Cake\Datasource\Exception\RecordNotFoundException;
try {
    $entity = $query->firstOrFail();
} catch (RecordNotFoundException $e) {
    // return 404 / fallback entity
}

Prevention

When it happens

Trigger: Calling ->firstOrFail() on a SELECT query whose WHERE conditions match zero rows — e.g. a wrong primary key value, a soft-delete/status filter excluding the row, or conditions built from unsanitized/unexpected input.

Common situations: Controller edit/view actions doing $articles->get($id) style lookups replaced by find()->where([...])->firstOrFail(); REST APIs returning 404; fixtures/seed data missing so lookups in tests fail; case-sensitivity or type mismatches (string '1' vs int 1) in the WHERE clause.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12). Data as JSON: /api/errors/c9549388be3f8a82. Report an issue: GitHub.

Appendix: source

Thrown at src/ORM/Query/SelectQuery.php:607

        if ($this->_dirty) {
            $this->limit(1);
        }

        return $this->all()->first();
    }

    /**
     * Get the first result from the executing query or raise an exception.
     *
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When there is no first record.
     * @return TSubject The first result from the ResultSet.
     */
    public function firstOrFail(): mixed
    {
        $entity = $this->first();
        if (!$entity) {
            $table = $this->getRepository();
            throw new RecordNotFoundException(sprintf(
                'Record not found in table `%s`.',
                $table->getTable(),
            ));
        }

        return $entity;
    }

    /**
     * Returns an array with the custom options that were applied to this query
     * and that were not already processed by another method in this class.
     *
     * ### Example:
     *
     * ```
     *  $query->applyOptions(['doABarrelRoll' => true, 'fields' => ['id', 'name']);
     *  $query->getOptions(); // Returns ['doABarrelRoll' => true]
     * ```

View on GitHub (pinned to 1128eba9b0)