quarkusio/quarkus · error · UnsupportedOperationException
Cannot use cursor-based pagination without sort criteria: us
Error message
Cannot use cursor-based pagination without sort criteria: use find(entityClass, query, sort) or findAll(entityClass, sort)
What it means
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.
Source
Thrown at extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java:186
filters = new HashMap<>();
filters.put(filterName, parameters);
}
public void page(Page page) {
this.page = page;
this.range = null;
this.keyedPage = null;
this.lastKeyedResult = null;
}
public void page(int pageIndex, int pageSize) {
page(Page.of(pageIndex, pageSize));
}
@SuppressWarnings("unchecked")
public void cursor(int pageIndex, int pageSize) {
if (sort == null || sort.getColumns().isEmpty()) {
throw new UnsupportedOperationException(
"Cannot use cursor-based pagination without sort criteria: use find(entityClass, query, sort) or findAll(entityClass, sort)");
}
List orders = PanacheJpaUtil.toHibernateOrders(entityClass, sort);
this.keyedPage = org.hibernate.query.Page.page(pageSize, pageIndex).keyedBy(orders);
this.lastKeyedResult = null;
this.page = null;
this.range = null;
}
public void nextPage() {
checkPagination();
if (keyedPage != null) {
if (lastKeyedResult == null) {
throw new UnsupportedOperationException(
"Cannot call nextPage() before fetching results with list()");
}
keyedPage = lastKeyedResult.getNextPage();
lastKeyedResult = null;View on GitHub (pinned to e1c734241f)
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
Example fix
// before
Person.findAll().cursor(0, 20);
// after
Person.findAll(Sort.ascending("id")).cursor(0, 20); Defensive patterns
Strategy: validation
Validate before calling
if (sort == null || sort.getColumns().isEmpty()) {
throw new IllegalArgumentException("Cursor pagination requires a Sort with at least one column");
} Type guard
boolean hasSort(io.quarkus.hibernate.orm.panache.common.Sort s) {
return s != null && !s.getColumns().isEmpty();
} Try / catch
try {
query.cursor(pageIndex, pageSize).list();
} catch (UnsupportedOperationException e) {
if (e.getMessage() != null && e.getMessage().contains("without sort criteria")) {
// fall back to offset pagination or add a Sort
} else throw e;
} Prevention
- 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
When it happens
Trigger: Creating a PanacheQuery with find/findAll without a Sort (or Sort.empty()) and then calling .cursor(pageIndex, pageSize) or .cursor(Page).
Common situations: 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.
Related errors
- Sort cannot be used with named query, add an "order by" clau
- Cannot call nextPage() before fetching results with list()
- Cannot call previousPage() before fetching results with list
- Sort cannot be used with named query, add an "order by" clau
- Cannot call a page related method, call page(Page) or page(i
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/3b17b09ebe201ab8.
Report an issue: GitHub.