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

  1. Do not call lastPage() with cursor-based pagination; iterate forward with nextPage()/hasNextPage() instead.
  2. Use offset pagination (query.page(pageIndex, pageSize)) if you truly need random-access navigation to the last page.
  3. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/2f5462e427982c83. Report an issue: GitHub.