hibernate/hibernate-orm · error · UnsupportedOperationException
Boolean expression does not support min()
Error message
Boolean expression does not support min()
What it means
SqmBooleanValuedSimplePath.min() is the mirror of max(): the min aggregate requires an orderable scalar type and Hibernate throws UnsupportedOperationException when .min() is invoked on a boolean-valued path. Like its sibling it fails during SQM construction, not at SQL execution. The message names min() explicitly.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmBooleanValuedSimplePath.java:89
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 before aggregating: "select min(cast(e.deleted as int)) from Document d" or cb.min(cb.toInteger(root.get("deleted"))).
- Express the intent directly: "select count(d) from Document d where d.deleted = false" or an every()/case-based predicate.
- Filter generic aggregation UIs to Number-typed expressions only.
- If native SQL min() on a boolean column is unavoidable, use a native query where the dialect decides.
Example fix
// before - deleted is boolean -> UnsupportedOperationException
Long r = em.createQuery("select min(cast(e.deleted as boolean)) from Document e", Long.class).getSingleResult();
// after - aggregate the integer cast
Integer r = em.createQuery("select min(cast(e.deleted as int)) from Document e", Integer.class).getSingleResult(); Defensive patterns
Strategy: validation
Validate before calling
static boolean minSupported(jakarta.persistence.criteria.Expression<?> e) {
Class<?> t = e.getJavaType();
if (t == null) return false;
if (Boolean.class == t || boolean.class == t) return false; // min() unsupported on boolean
return Number.class.isAssignableFrom(t) || 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.min(expr);
} catch (UnsupportedOperationException e) {
if (Boolean.class == expr.getJavaType()) {
return cb.min(cb.toInteger((jakarta.persistence.criteria.Expression<Boolean>) expr));
}
throw e;
} Prevention
- Express 'all rows satisfy flag' as a count/where predicate, not min(flag).
- Keep a type allowlist for aggregate-able expressions in query-builder UIs.
- Cast boolean columns to int in HQL before min/max.
When it happens
Trigger: HQL "select min(e.deleted) from Document d" where deleted is boolean; Criteria code calling .min() on root.get("enabled") of a Boolean attribute; generic min/max toggle in a query builder applied to a flag column.
Common situations: Dashboards computing 'all rows still enabled' as min(flag); T-SQL/MySQL-style boolean aggregate habits carried into HQL; soft-delete flags aggregated with min() to check whether any row is deleted.
Related errors
- Boolean expression does not support max()
- 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/bed8cc0d2ff024b5.
Report an issue: GitHub.