{"record":{"id":"3c31809d97e179e9","repo":"hibernate/hibernate-orm","slug":"fetch-clause-may-not-be-null-3c3180","errorCode":null,"errorMessage":"Fetch clause may not be null","messagePattern":"Fetch clause may not be null","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QueryPart.java","lineNumber":113,"sourceCode":"\t\treturn offsetClauseExpression;\n\t}\n\n\tpublic void setOffsetClauseExpression(Expression offsetClauseExpression) {\n\t\tthis.offsetClauseExpression = offsetClauseExpression;\n\t}\n\n\tpublic Expression getFetchClauseExpression() {\n\t\treturn fetchClauseExpression;\n\t}\n\n\tpublic void setFetchClauseExpression(Expression fetchClauseExpression, FetchClauseType fetchClauseType) {\n\t\tif ( fetchClauseExpression == null ) {\n\t\t\tthis.fetchClauseExpression = null;\n\t\t\tthis.fetchClauseType = FetchClauseType.ROWS_ONLY;\n\t\t}\n\t\telse {\n\t\t\tif ( fetchClauseType == null ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Fetch clause may not be null\" );\n\t\t\t}\n\t\t\tthis.fetchClauseExpression = fetchClauseExpression;\n\t\t\tthis.fetchClauseType = fetchClauseType;\n\t\t}\n\t}\n\n\tpublic FetchClauseType getFetchClauseType() {\n\t\treturn fetchClauseType;\n\t}\n\n}\n","sourceCodeStart":95,"sourceCodeEnd":125,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QueryPart.java#L95-L125","documentation":"QueryPart.setFetchClauseExpression(Expression, FetchClauseType) backs HQL/JPQL 'fetch first/next' clauses. Passing a non-null expression together with a null FetchClauseType is contradictory - the AST cannot represent 'fetch N' without knowing whether it is ROWS_ONLY, ROWS_WITH_TIES, PERCENT_ONLY or PERCENT_WITH_TIES - so an IllegalArgumentException is thrown. Passing a null expression is the supported way to clear the clause and resets both fields.","triggerScenarios":"Programmatic construction of a QueryPart (custom translators, criteria-to-SQL AST code) calling setFetchClauseExpression(expr, null); copy/clone routines that copy the expression but not the type; misuse of the setter with a non-null expression and missing type.","commonSituations":"Custom SqmTranslator/SqlAstCreation extensions building pagination; porting code between Hibernate versions where the setter signature changed; dialect-specific fetch-clause emulation setting the expression programmatically.","solutions":["Pass a concrete FetchClauseType (usually FetchClauseType.ROWS_ONLY) whenever the expression is non-null","To clear the fetch clause call setFetchClauseExpression(null, null) - the null branch resets both fields","Validate arguments up front: only (null, ...) or (expr, non-null type) are legal combinations"],"exampleFix":"// before\nqueryPart.setFetchClauseExpression( rowCount, null ); // throws\n\n// after\nqueryPart.setFetchClauseExpression( rowCount, FetchClauseType.ROWS_ONLY );","handlingStrategy":"validation","validationCode":"void applyFetchClause(QueryPart part, Expression expr, FetchClauseType type) {\n    if ( expr == null ) {\n        part.setFetchClauseExpression( null, null );\n    } else {\n        Objects.requireNonNull( type, \"FetchClauseType required for non-null expression\" );\n        part.setFetchClauseExpression( expr, type );\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair a non-null fetch expression with a concrete FetchClauseType (usually ROWS_ONLY)","Clear fetch clauses with setFetchClauseExpression(null, null)","Treat (expr != null && type == null) as a programmer error and assert it before calling"],"tags":["hibernate","orm","sql-ast","pagination","fetch-clause","illegal-argument"],"backgroundTag":"null-argument-validation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}