hibernate/hibernate-orm · error · UnsupportedOperationException
Cannot apply `countDistinct()` to predicates
Error message
Cannot apply `countDistinct()` to predicates
What it means
AbstractSqmPredicate.countDistinct throws UnsupportedOperationException for the same reason as count(): COUNT(DISTINCT ...) is an aggregate over an expression producing values per row, and a predicate is a boolean condition, not a per-row value expression. The method is inherited from JpaExpression's interface surface, so it is visible on predicates, but Hibernate's predicate base class rejects it at build time.
Solutions
- Count distinct values of a path under the predicate: `query.select( cb.countDistinct( root.get("x")) ).where( predicate )`
- For CASE-based distinct counts, apply countDistinct() to the case expression, not the predicate
- Type-guard generic code: skip or throw your own clear error when the node is a JpaPredicate
- Verify the intended SQL first — COUNT(DISTINCT <boolean>) is almost never what the requirement means
Example fix
// before
JpaPredicate active = cb.isTrue( root.get("active") );
expr = active.countDistinct(); // UnsupportedOperationException
// after
query.select( cb.countDistinct( root.get("department") ) ).where( active ); Defensive patterns
Strategy: type-guard
Validate before calling
if (expr instanceof org.hibernate.query.criteria.JpaPredicate) {
throw new IllegalArgumentException("countDistinct() not applicable to predicates");
} Type guard
static boolean isCountable(org.hibernate.query.criteria.JpaExpression<?> e) {
return !(e instanceof org.hibernate.query.criteria.JpaPredicate);
} Prevention
- Use cb.countDistinct(path) in the select list with the predicate as where
- Apply countDistinct to value expressions only
- Guard generic aggregation wrappers with a predicate type check
When it happens
Trigger: Calling `predicate.countDistinct()` — e.g. `cb.equal( root.get("status"), "A" ).countDistinct()`; generic distinct-count builders applying countDistinct() to Expression<?> without type checks; attempts to emulate COUNT(DISTINCT CASE WHEN ... THEN x END) by counting the predicate itself.
Common situations: Distinct-count reporting code paths that handle all expressions uniformly; porting SQL like `count(distinct (a=b))` to criteria; wrapper APIs exposing countDistinct() on every node descending from JpaExpression.
Related errors
- Cannot apply `count()` to predicates
- Boolean expression does not support max()
- Boolean expression does not support max()
- Boolean expression does not support min()
- Boolean expression does not support min()
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/79504201924dc65d.
Report an issue: GitHub.
Appendix: source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/predicate/AbstractSqmPredicate.java:78
}
@Nonnull
@Override
public List<Expression<Boolean>> getExpressions() {
/// most predicates do not have sub-predicates
return new ArrayList<>(0);
}
@Nonnull
@Override
public JpaNumericExpression<Long> count() {
throw new UnsupportedOperationException( "Cannot apply `count()` to predicates" );
}
@Nonnull
@Override
public JpaNumericExpression<Long> countDistinct() {
throw new UnsupportedOperationException( "Cannot apply `countDistinct()` to predicates" );
}
@Nonnull
@Override
public SqmBooleanExpression coalesce(@Nonnull Expression<? extends Boolean> y) {
return (SqmBooleanExpression) super.coalesce( y );
}
@Nonnull
@Override
public SqmBooleanExpression coalesce(Boolean y) {
return (SqmBooleanExpression) super.coalesce( y );
}
@Nonnull
@Override
public SqmBooleanExpression nullif(@Nonnull Expression<? extends Boolean> y) {
return (SqmBooleanExpression) super.nullif( y );View on GitHub (pinned to fad1729dce)