hibernate/hibernate-orm · error · UnsupportedOperationException
Boolean expression does not support max()
Error message
Boolean expression does not support max()
What it means
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.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmBooleanValuedSimplePath.java:83
return new SqmBooleanExpressionWrapper( nodeBuilder().coalesce( this, y ) );
}
@Nonnull
@Override
public SqmBooleanExpression nullif(@Nonnull Expression<? extends Boolean> y) {
return new SqmBooleanExpressionWrapper( nodeBuilder().nullif( this, y ) );
}
@Nonnull
@Override
public SqmBooleanExpression nullif(Boolean y) {
return new SqmBooleanExpressionWrapper( nodeBuilder().nullif( this, y ) );
}
@Nonnull
@Override
public SqmBooleanExpression max() {
throw new UnsupportedOperationException( "Boolean expression does not support max()" );
}
@Nonnull
@Override
public SqmBooleanExpression min() {
throw new UnsupportedOperationException( "Boolean expression does not support min()" );
}
}
View on GitHub (pinned to fad1729dce)
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.
Example fix
// before - active is boolean -> UnsupportedOperationException at query build
Object r = em.createQuery("select max(e.active) from Employee e").getSingleResult();
// after - aggregate over the cast integer value
Integer r = em.createQuery("select max(cast(e.active as int)) from Employee e", Integer.class).getSingleResult(); Defensive patterns
Strategy: validation
Validate before calling
// Check the operand type before aggregating
static boolean maxSupported(jakarta.persistence.criteria.Expression<?> e) {
Class<?> t = e.getJavaType();
return Number.class.isAssignableFrom(t) || (t != null && t.isPrimitive())
|| java.time.temporal.Temporal.class.isAssignableFrom(t)
|| String.class == t;
} Type guard
static boolean isBooleanExpr(jakarta.persistence.criteria.Expression<?> e) {
return Boolean.class == e.getJavaType() || boolean.class == e.getJavaType();
} Try / catch
try {
return cb.max(expr);
} catch (UnsupportedOperationException e) {
if (Boolean.class == expr.getJavaType()) {
return cb.max(cb.toInteger((jakarta.persistence.criteria.Expression<Boolean>) expr));
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Boolean expression does not support min()
- Could not interpret attribute '%s' of basic-valued path '%s'
- Cte root does not have an entity type. Use getReferencedPath
- Embeddable paths cannot be TREAT-ed to an entity type
- Whatever JPA
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/76514ceda217c49d.
Report an issue: GitHub.