greenrobot/greenDAO · error · IllegalStateException

Offset must be set with QueryBuilder before it can be used…

Error message

Offset must be set with QueryBuilder before it can be used here

What it means

setOffset only rewrites an existing OFFSET placeholder parameter. If the Query was built without QueryBuilder.offset(int), offsetPosition is -1 and IllegalStateException is thrown because there is no OFFSET slot in the prepared SQL.

Solutions

  1. Include .offset(n) in the QueryBuilder before build() so the OFFSET parameter slot exists
  2. Rebuild the query with the desired initial offset when paging requirements change
  3. Prefer setLimit + setOffset on a query built with both limit and offset for paging

Example fix

// before
Query<User> q = userDao.queryBuilder().where(...).limit(20).build();
q.setOffset(20); // throws
// after
Query<User> q = userDao.queryBuilder().where(...).limit(20).offset(0).build();
q.setOffset(20); // OK
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the query was built with .offset()
Query<User> q = qb.where(...).limit(pageSize).offset(0).build();

Try / catch

try {
    query.setOffset(newOffset);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Offset must be set with QueryBuilder")) {
        query = qb.where(...).limit(pageSize).offset(newOffset).build();
    }
}

Prevention

When it happens

Trigger: Calling query.setOffset(n) on a Query built without .offset() in the QueryBuilder chain.

Common situations: Implementing incremental paging (moving OFFSET) but forgetting to seed the initial offset in the builder; refactoring queries from fixed to dynamic offsets.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of greenrobot/greenDAO@0bbb338e17 (2026-09-08). Data as JSON: /api/errors/6498945806a3ae49. Report an issue: GitHub.

Appendix: source

Thrown at DaoCore/src/main/java/org/greenrobot/greendao/query/AbstractQueryWithLimit.java:70

     * have been called on the QueryBuilder that created this Query object.
     */
    public void setLimit(int limit) {
        checkThread();
        if (limitPosition == -1) {
            throw new IllegalStateException("Limit must be set with QueryBuilder before it can be used here");
        }
        parameters[limitPosition] = Integer.toString(limit);
    }

    /**
     * Sets the offset for results returned by this Query. {@link org.greenrobot.greendao.query.QueryBuilder#offset(int)} must
     * have been called on
     * the QueryBuilder that created this Query object.
     */
    public void setOffset(int offset) {
        checkThread();
        if (offsetPosition == -1) {
            throw new IllegalStateException("Offset must be set with QueryBuilder before it can be used here");
        }
        parameters[offsetPosition] = Integer.toString(offset);
    }

}

View on GitHub (pinned to 0bbb338e17)