quarkusio/quarkus · error · UnsupportedOperationException

Cannot call hasPreviousPage() before fetching results with l

Error message

Cannot call hasPreviousPage() before fetching results with list()

What it means

With cursor-based (keyed) pagination, hasPreviousPage() relies on the cursor state of the previously fetched result. If no page has been fetched via list() yet, Panache throws UnsupportedOperationException because there is no cursor indicating whether the current page is the first one.

Source

Thrown at extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/CommonPanacheQueryImpl.java:263

    }

    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() {
        checkPagination();
        if (keyedPage != null) {
            if (lastKeyedResult == null) {
                throw new UnsupportedOperationException(
                        "Cannot call hasPreviousPage() before fetching results with list()");
            }
            return !lastKeyedResult.isFirstPage();
        }
        return page.index > 0;
    }

    public int pageCount() {
        checkPagination();
        long count = count();
        if (count == 0)
            return 1; // a single page of zero results
        int pageSize = keyedPage != null ? keyedPage.getPage().getSize() : page.size;
        return (int) Math.ceil((double) count / (double) pageSize);
    }

    public Page page() {
        checkPagination();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Call list() first, then call hasPreviousPage().
  2. Use offset pagination (page(int, int)) if you need pre-fetch page flags.
  3. Track the first page yourself: keyed pagination started at the beginning implies no previous page until you have navigated.

Example fix

// before
query.page(KeyedPage.of(KeyedPage.PREVIOUS, 50));
boolean prev = query.hasPreviousPage(); // throws

// after
query.page(KeyedPage.of(KeyedPage.PREVIOUS, 50));
List<MyEntity> page = query.list();
boolean prev = query.hasPreviousPage();
Defensive patterns

Strategy: validation

Validate before calling

if (lastFetchedPage == null) {
    query.list(); // fetch current page first
}
boolean hasPrev = query.hasPreviousPage();

Try / catch

try {
    return query.hasPreviousPage();
} catch (UnsupportedOperationException e) {
    query.list();
    return query.hasPreviousPage();
}

Prevention

When it happens

Trigger: Calling hasPreviousPage() on a query paginated with KeyedPage before calling list()/stream() at least once.

Common situations: Building UI pagination controls (prev/next flags) before executing the query, a pattern that works with offset pagination but not with keyed pagination.

Related errors


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