{"record":{"id":"3b17b09ebe201ab8","repo":"quarkusio/quarkus","slug":"cannot-use-cursor-based-pagination-without-sort-cr","errorCode":null,"errorMessage":"Cannot use cursor-based pagination without sort criteria: use find(entityClass, query, sort) or findAll(entityClass, sort)","messagePattern":"Cannot use cursor-based pagination without sort criteria: use find\\(entityClass, query, sort\\) or findAll\\(entityClass, sort\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java","lineNumber":186,"sourceCode":"            filters = new HashMap<>();\n        filters.put(filterName, parameters);\n    }\n\n    public void page(Page page) {\n        this.page = page;\n        this.range = null;\n        this.keyedPage = null;\n        this.lastKeyedResult = null;\n    }\n\n    public void page(int pageIndex, int pageSize) {\n        page(Page.of(pageIndex, pageSize));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public void cursor(int pageIndex, int pageSize) {\n        if (sort == null || sort.getColumns().isEmpty()) {\n            throw new UnsupportedOperationException(\n                    \"Cannot use cursor-based pagination without sort criteria: use find(entityClass, query, sort) or findAll(entityClass, sort)\");\n        }\n        List orders = PanacheJpaUtil.toHibernateOrders(entityClass, sort);\n        this.keyedPage = org.hibernate.query.Page.page(pageSize, pageIndex).keyedBy(orders);\n        this.lastKeyedResult = null;\n        this.page = null;\n        this.range = null;\n    }\n\n    public void nextPage() {\n        checkPagination();\n        if (keyedPage != null) {\n            if (lastKeyedResult == null) {\n                throw new UnsupportedOperationException(\n                        \"Cannot call nextPage() before fetching results with list()\");\n            }\n            keyedPage = lastKeyedResult.getNextPage();\n            lastKeyedResult = null;","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java#L168-L204","documentation":"Cursor (keyset/keyed) pagination derives page boundaries from sorted column values; without at least one sort column the key is undefined. Panache throws UnsupportedOperationException when cursor(pageIndex, pageSize) is called on a query with no Sort or an empty Sort.","triggerScenarios":"Creating a PanacheQuery with find/findAll without a Sort (or Sort.empty()) and then calling .cursor(pageIndex, pageSize) or .cursor(Page).","commonSituations":"Adding cursor pagination to an existing findAll() call that never needed sorting; sort built conditionally so it ends up empty at runtime; upgrading Panache and switching from offset to cursor-based paging.","solutions":["Pass a Sort with at least one stable unique column: findAll(Sort.ascending(\"id\"))","Ensure the Sort is not conditionally left empty at runtime","Fall back to page() based offset pagination if no meaningful sort exists"],"exampleFix":"// before\nPerson.findAll().cursor(0, 20);\n// after\nPerson.findAll(Sort.ascending(\"id\")).cursor(0, 20);","handlingStrategy":"validation","validationCode":"if (sort == null || sort.getColumns().isEmpty()) {\n    throw new IllegalArgumentException(\"Cursor pagination requires a Sort with at least one column\");\n}","typeGuard":"boolean hasSort(io.quarkus.hibernate.orm.panache.common.Sort s) {\n    return s != null && !s.getColumns().isEmpty();\n}","tryCatchPattern":"try {\n    query.cursor(pageIndex, pageSize).list();\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"without sort criteria\")) {\n        // fall back to offset pagination or add a Sort\n    } else throw e;\n}","preventionTips":["Always pass a Sort (ideally including a unique column) when using cursor()","Guard helper APIs so an empty/conditional Sort falls back to page()","Include a primary key in the sort for stable keyset pagination"],"tags":["quarkus","panache","pagination","sort"],"backgroundTag":"cursor-pagination-requires-sort","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}