{"record":{"id":"76514ceda217c49d","repo":"hibernate/hibernate-orm","slug":"boolean-expression-does-not-support-max","errorCode":null,"errorMessage":"Boolean expression does not support max()","messagePattern":"Boolean expression does not support max\\(\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmBooleanValuedSimplePath.java","lineNumber":83,"sourceCode":"\t\treturn new SqmBooleanExpressionWrapper( nodeBuilder().coalesce( this, y ) );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic SqmBooleanExpression nullif(@Nonnull Expression<? extends Boolean> y) {\n\t\treturn new SqmBooleanExpressionWrapper( nodeBuilder().nullif( this, y ) );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic SqmBooleanExpression nullif(Boolean y) {\n\t\treturn new SqmBooleanExpressionWrapper( nodeBuilder().nullif( this, y ) );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic SqmBooleanExpression max() {\n\t\tthrow new UnsupportedOperationException( \"Boolean expression does not support max()\" );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic SqmBooleanExpression min() {\n\t\tthrow new UnsupportedOperationException( \"Boolean expression does not support min()\" );\n\t}\n}\n","sourceCodeStart":65,"sourceCodeEnd":92,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmBooleanValuedSimplePath.java#L65-L92","documentation":"SqmBooleanValuedSimplePath.max() (inherited surface: SqmComparableExpression.max(), the criteria counterpart of HQL max()) throws UnsupportedOperationException because the max aggregate is defined over ordered scalar types and Hibernate's type system does not order booleans. Calling .max() on a boolean-typed path/expression fails immediately while the SQM tree is assembled. The SQL is never produced.","triggerScenarios":"HQL \"select max(e.active) from Employee e\" where active is a boolean column; Criteria code ((JpaExpression<Boolean>) root.get(\"active\")).max(); HQLQueryBuilder DSLs that call max() on whatever selection the user picked, including flags.","commonSituations":"Porting SQL Server habits where max() over a bit column is accepted; report queries that want 'any row active' or 'latest flag value' semantics; generic aggregation UIs letting users apply max to every numeric-looking column, including boolean flags stored as true/false.","solutions":["Cast the boolean to an integer before aggregating: \"select max(cast(e.active as int)) from Employee e\" or cb.max(cb.toInteger(root.get(\"active\"))).","If you need 'at least one true' semantics, use a case/count instead: \"select case when count(e.id) > 0 then true else false end ... where e.active = true\".","Restrict generic aggregation code so max() is only offered for Number-typed expressions.","Model the flag as a smallint column in the database if SQL-level max() over it is a hard requirement."],"exampleFix":"// before - active is boolean -> UnsupportedOperationException at query build\nObject r = em.createQuery(\"select max(e.active) from Employee e\").getSingleResult();\n\n// after - aggregate over the cast integer value\nInteger r = em.createQuery(\"select max(cast(e.active as int)) from Employee e\", Integer.class).getSingleResult();","handlingStrategy":"validation","validationCode":"// Check the operand type before aggregating\nstatic boolean maxSupported(jakarta.persistence.criteria.Expression<?> e) {\n    Class<?> t = e.getJavaType();\n    return Number.class.isAssignableFrom(t) || (t != null && t.isPrimitive())\n        || java.time.temporal.Temporal.class.isAssignableFrom(t)\n        || String.class == t;\n}","typeGuard":"static boolean isBooleanExpr(jakarta.persistence.criteria.Expression<?> e) {\n    return Boolean.class == e.getJavaType() || boolean.class == e.getJavaType();\n}","tryCatchPattern":"try {\n    return cb.max(expr);\n} catch (UnsupportedOperationException e) {\n    if (Boolean.class == expr.getJavaType()) {\n        return cb.max(cb.toInteger((jakarta.persistence.criteria.Expression<Boolean>) expr));\n    }\n    throw e;\n}","preventionTips":["In dynamic-report builders, offer max/min only for numeric/temporal/string columns.","Cast booleans to int at the query level when aggregates are required.","Unit-test the aggregation picker with boolean flag columns present."],"tags":["hibernate","hql","criteria-api","aggregate","boolean","sqm"],"backgroundTag":"aggregate-on-boolean","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}