{"record":{"id":"d8259cbca293b9b2","repo":"cakephp/cakephp","slug":"page-number-s-could-not-be-found","errorCode":null,"errorMessage":"Page number `%s` could not be found.","messagePattern":"Page number `(.+?)` could not be found\\.","errorType":"exception","errorClass":"PageOutOfBoundsException","httpStatus":null,"severity":"warning","filePath":"src/Datasource/Paging/NumericPaginator.php","lineNumber":257,"sourceCode":"        }\n\n        assert(\n            $target instanceof RepositoryInterface,\n            'Pagination target must be an instance of `' . QueryInterface::class\n                . '` or `' . RepositoryInterface::class . '`.',\n        );\n\n        $data = $this->extractData($target, $params, $settings);\n        $query = $this->getQuery($target, $query, $data);\n\n        $countQuery = clone $query;\n        $items = $this->getItems($query, $data);\n        $this->pagingParams['count'] = count($items);\n        $this->pagingParams['totalCount'] = $this->getCount($countQuery, $data);\n\n        $pagingParams = $this->buildParams($data);\n        if ($pagingParams['requestedPage'] > $pagingParams['currentPage']) {\n            throw new PageOutOfBoundsException([\n                'requestedPage' => $pagingParams['requestedPage'],\n                'pagingParams' => $pagingParams,\n            ]);\n        }\n\n        return $this->buildPaginated($items, $pagingParams);\n    }\n\n    /**\n     * Build paginated result set.\n     *\n     * @param \\Cake\\Datasource\\ResultSetInterface<int, mixed> $items\n     * @param array $pagingParams\n     * @return \\Cake\\Datasource\\Paging\\PaginatedInterface<int, mixed>\n     */\n    protected function buildPaginated(ResultSetInterface $items, array $pagingParams): PaginatedInterface\n    {\n        return new PaginatedResultSet($items, $pagingParams);","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/cakephp/cakephp/blob/1128eba9b09f1946df684811350e26f2cef68fac/src/Datasource/Paging/NumericPaginator.php#L239-L275","documentation":"After fetching the items and counts, the paginator compares the requested page number (from request params) to the computed current page (total count / page size). If the user asked for a page beyond the last existing page, PageOutOfBoundsException is thrown; its message renders the requested page number.","triggerScenarios":"Requesting ?page=99 when only 3 pages of results exist; requesting page > 1 on an empty or filtered-down result set; stale pagination links after records were deleted; a page parameter supplied as a huge number.","commonSituations":"Users bookmarking deep pagination links that become invalid after data changes; bots crawling page=1..N indefinitely; after narrowing a search filter, the retained page number exceeds the new page count.","solutions":["Wrap paginate() in try/catch for PageOutOfBoundsException and redirect to page 1 (the standard CakePHP exception-renderer behavior).","Validate/sanitize the requested page before paginating and clamp it to an available range when you can count results beforehand.","In the exception handler, map PageOutOfBoundsException to a 404 so clients stop crawling invalid pages.","Regenerate pagination links from the current paging params instead of persisting absolute page numbers."],"exampleFix":"// before\n$results = $paginator->paginate($query, $this->request->getQueryParams());\n// after\ntry {\n    $results = $paginator->paginate($query, $this->request->getQueryParams());\n} catch (PageOutOfBoundsException $e) {\n    $params = $this->request->getQueryParams();\n    unset($params['page']);\n    return $this->redirect(['?' => $params]);\n}","handlingStrategy":"try-catch","validationCode":"$page = max(1, (int)($params['page'] ?? 1));\nif ($page > 10000) { // sanity cap\n    $page = 1;\n}\n$params['page'] = $page;\n$results = $paginator->paginate($query, $params);","typeGuard":null,"tryCatchPattern":"try {\n    $results = $paginator->paginate($query, $params);\n} catch (\\Cake\\Datasource\\Exception\\PageOutOfBoundsException $e) {\n    unset($params['page']);\n    $results = $paginator->paginate($query, $params); // or redirect to page 1\n}","preventionTips":["Catch PageOutOfBoundsException centrally (exception renderer -> 404).","Drop or clamp the page param when filters/search terms change.","Cap the maximum page number accepted from requests to stop crawler abuse."],"tags":["cakephp","pagination","out-of-range"],"backgroundTag":"value-out-of-range","analyzedSha":"1128eba9b09f1946df684811350e26f2cef68fac","analyzedAt":"2026-09-12T12:07:00.388Z","contentChangedAt":"2026-09-12T12:07:00.388Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}