quarkusio/quarkus · error · UnsupportedOperationException
Cannot navigate to last page in cursor-based pagination
Error message
Cannot navigate to last page in cursor-based pagination
What it means
In Panache, when a query is paginated with keyset (cursor-based) pagination via KeyedPage, the total page count is unknown because it would require counting the whole result set. Therefore lastPage(), which navigates by page index, cannot work and throws UnsupportedOperationException.
Source
Thrown at extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java:241
page(page.previous());
}
}
@SuppressWarnings("unchecked")
public void firstPage() {
checkPagination();
if (keyedPage != null) {
keyedPage = keyedPage.getPage().first().keyedBy((List) keyedPage.getKeyDefinition());
lastKeyedResult = null;
} else {
page(page.first());
}
}
public void lastPage() {
checkPagination();
if (keyedPage != null) {
throw new UnsupportedOperationException(
"Cannot navigate to last page in cursor-based pagination");
}
page(page.index(pageCount() - 1));
}
public boolean hasNextPage() {
checkPagination();
if (keyedPage != null) {
if (lastKeyedResult == null) {
throw new UnsupportedOperationException(
"Cannot call hasNextPage() before fetching results with list()");
}
return !lastKeyedResult.isLastPage();
}
return page.index < (pageCount() - 1);
}
public boolean hasPreviousPage() {View on GitHub (pinned to e1c734241f)
Solutions
- Do not call lastPage() with cursor-based pagination; iterate forward with nextPage()/hasNextPage() instead.
- Use offset pagination (query.page(pageIndex, pageSize)) if you truly need random-access navigation to the last page.
- If you need the last items, sort descending and use firstPage() with the reversed sort.
Example fix
// before
query.page(KeyedPage.of(KeyedPage.LAST, pageSize));
query.lastPage(); // throws
// after
query.page(KeyedPage.of(KeyedPage.NEXT, pageSize));
while (query.hasNextPage()) {
query.nextPage();
} Defensive patterns
Strategy: validation
Validate before calling
if (queryIsKeyedPaginated) {
throw new IllegalArgumentException("lastPage() is unsupported with cursor-based pagination; use nextPage()/hasNextPage()");
} Try / catch
try {
query.lastPage();
} catch (UnsupportedOperationException e) {
// fall back to iterating forward or offset pagination
} Prevention
- Never mix keyed pagination with index-based navigation helpers (firstPage/lastPage).
- Encapsulate pagination strategy in one helper so keyed/offset differences are hidden.
- Reverse the sort order instead of jumping to the last page.
When it happens
Trigger: Calling query.page(KeyedPage.of(...)) (or a keyed page variant) on a PanacheQuery/CommonPanacheQueryImpl and then calling lastPage().
Common situations: Developers switching from offset pagination to cursor-based pagination for large tables and keeping their old page-navigation code (firstPage/lastPage/nextPage by index) unchanged.
Related errors
- Cursor-based pagination is not supported by Hibernate Reacti
- Cursor-based pagination is not supported by Hibernate Reacti
- Cannot call nextPage() before fetching results with list()
- Cannot call previousPage() before fetching results with list
- Cannot call hasNextPage() before fetching results with list(
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/2f5462e427982c83.
Report an issue: GitHub.