{"record":{"id":"6498945806a3ae49","repo":"greenrobot/greenDAO","slug":"offset-must-be-set-with-querybuilder-before-it-can","errorCode":null,"errorMessage":"Offset must be set with QueryBuilder before it can be used here","messagePattern":"Offset must be set with QueryBuilder before it can be used here","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"DaoCore/src/main/java/org/greenrobot/greendao/query/AbstractQueryWithLimit.java","lineNumber":70,"sourceCode":"     * have been called on the QueryBuilder that created this Query object.\n     */\n    public void setLimit(int limit) {\n        checkThread();\n        if (limitPosition == -1) {\n            throw new IllegalStateException(\"Limit must be set with QueryBuilder before it can be used here\");\n        }\n        parameters[limitPosition] = Integer.toString(limit);\n    }\n\n    /**\n     * Sets the offset for results returned by this Query. {@link org.greenrobot.greendao.query.QueryBuilder#offset(int)} must\n     * have been called on\n     * the QueryBuilder that created this Query object.\n     */\n    public void setOffset(int offset) {\n        checkThread();\n        if (offsetPosition == -1) {\n            throw new IllegalStateException(\"Offset must be set with QueryBuilder before it can be used here\");\n        }\n        parameters[offsetPosition] = Integer.toString(offset);\n    }\n\n}\n","sourceCodeStart":52,"sourceCodeEnd":76,"githubUrl":"https://github.com/greenrobot/greenDAO/blob/0bbb338e17c4cf28aba5aae62d42f73f50186157/DaoCore/src/main/java/org/greenrobot/greendao/query/AbstractQueryWithLimit.java#L52-L76","documentation":"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.","triggerScenarios":"Calling query.setOffset(n) on a Query built without .offset() in the QueryBuilder chain.","commonSituations":"Implementing incremental paging (moving OFFSET) but forgetting to seed the initial offset in the builder; refactoring queries from fixed to dynamic offsets.","solutions":["Include .offset(n) in the QueryBuilder before build() so the OFFSET parameter slot exists","Rebuild the query with the desired initial offset when paging requirements change","Prefer setLimit + setOffset on a query built with both limit and offset for paging"],"exampleFix":"// before\nQuery<User> q = userDao.queryBuilder().where(...).limit(20).build();\nq.setOffset(20); // throws\n// after\nQuery<User> q = userDao.queryBuilder().where(...).limit(20).offset(0).build();\nq.setOffset(20); // OK","handlingStrategy":"try-catch","validationCode":"// ensure the query was built with .offset()\nQuery<User> q = qb.where(...).limit(pageSize).offset(0).build();","typeGuard":null,"tryCatchPattern":"try {\n    query.setOffset(newOffset);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Offset must be set with QueryBuilder\")) {\n        query = qb.where(...).limit(pageSize).offset(newOffset).build();\n    }\n}","preventionTips":["Seed .offset(0) in the builder when doing incremental paging","Pair .limit() with .offset() whenever paging is planned","Rebuild the Query if offset support is needed later"],"tags":["greendao","orm","query","pagination"],"backgroundTag":"invalid-state-transition","analyzedSha":"0bbb338e17c4cf28aba5aae62d42f73f50186157","analyzedAt":"2026-09-08T03:22:36.050Z","contentChangedAt":"2026-09-08T03:22:36.050Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}