{"record":{"id":"2b5485b02e3eb9ad","repo":"apache/seatunnel","slug":"page-number-exceeds-total-pages","errorCode":null,"errorMessage":"Page number exceeds total pages","messagePattern":"Page number exceeds total pages","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/rest/servlet/PageBaseServlet.java","lineNumber":57,"sourceCode":"            HttpServletRequest req, HttpServletResponse resp, JsonArray jsonArray)\n            throws IOException {\n        int total = jsonArray.size();\n\n        // fetch pagination params, if page exist, then paginate data，pagination data format like:\n        // {\"data\": [], \"total\": 10}\n        Map<String, String> parameterMap = getParameterMap(req);\n        if (parameterMap != null && parameterMap.containsKey(pageParam)) {\n            int page = Integer.parseInt(parameterMap.get(pageParam));\n            int rows =\n                    parameterMap.get(rowsParam) != null\n                            ? Integer.parseInt(parameterMap.get(rowsParam))\n                            : 10;\n            int start = (page - 1) * rows;\n            if (start > total || page < 1) {\n                throw new IllegalArgumentException(\n                        page < 1\n                                ? \"Page number must be greater than 0\"\n                                : \"Page number exceeds total pages\");\n            }\n            JsonArray paginatedArray = new JsonArray();\n            jsonArray\n                    .values()\n                    .subList(start, Math.min(start + rows, total))\n                    .forEach(\n                            t -> {\n                                paginatedArray.add(t);\n                            });\n            JsonObject paginatedObj = new JsonObject();\n            paginatedObj.add(\"data\", paginatedArray);\n            paginatedObj.add(\"total\", total);\n            writeJson(resp, paginatedObj);\n        } else {\n            writeJson(resp, jsonArray);\n        }\n    }\n}","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/rest/servlet/PageBaseServlet.java#L39-L75","documentation":"PageBaseServlet.writeJsonWithPagination rejects a page whose computed start offset exceeds the total number of records with 'Page number exceeds total pages'. This happens when start=(page-1)*rows > total, i.e. the requested page lies past the last page of data.","triggerScenarios":"GET a paginated endpoint with a page number beyond the available rows, e.g. 200 total rows with rows=10 and page=21+; also triggered when the result set shrinks (filters/new data) between requests and the client retries the old page.","commonSituations":"Deep pagination after data deletion or job retention cleanup; saved UI links to a high page number; stale 'next page' links after the list shrank; large page values typed by users or tests.","solutions":["Request a page within range; compute lastPage = max(1, ceil(total/rows)) client-side","When a filter reduces the result set, reset pagination to page 1","Handle the error by clamping to the last page and retrying","Return 400 with total page count in the body so clients can self-correct"],"exampleFix":"// before\n// results shrank from 300 to 120 rows, still fetching page 30\nfetch(`/finished-jobs?page=30&rows=10`);\n// after\nconst lastPage = Math.max(1, Math.ceil(total / rows));\nfetch(`/finished-jobs?page=${Math.min(page, lastPage)}&rows=10`);","handlingStrategy":"validation","validationCode":"int lastPage = Math.max(1, (int) Math.ceil((double) total / rows));\nint safePage = Math.min(page, lastPage);","typeGuard":"boolean isWithinRange(int page, int total, int rows) { return page >= 1 && (page - 1) * rows < total; }","tryCatchPattern":"try { fetchPage(page); } catch (IllegalArgumentException e) { fetchPage(Math.max(1, page - 1)); } // walk back when data shrank","preventionTips":["Reset to page 1 whenever filters change","Refresh total counts before deep pagination","Cap UI pagination controls at the last page"],"tags":["rest","pagination","validation"],"backgroundTag":"value-out-of-range","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}