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.

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)

Solutions

  1. Count distinct values of a path under the predicate: `query.select( cb.countDistinct( root.get("x")) ).where( predicate )`
  2. For CASE-based distinct counts, apply countDistinct() to the case expression, not the predicate
  3. Type-guard generic code: skip or throw your own clear error when the node is a JpaPredicate
  4. 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

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


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/79504201924dc65d. Report an issue: GitHub.