hibernate/hibernate-orm · error · UnsupportedOperationException

Boolean expression does not support min()

Error message

Boolean expression does not support min()

What it means

SqmBooleanExpressionWrapper.min() mirrors max(): Boolean-typed wrapped expressions cannot be minimized in SQM because there is no Boolean min aggregate semantics, so Hibernate throws UnsupportedOperationException('Boolean expression does not support min()') as soon as the criteria tree is built.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmBooleanExpressionWrapper.java:65

		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()" );
	}

	@Override
	public SqmExpression<Boolean> copy(SqmCopyContext context) {
		return wrappedExpression.copy( context );
	}

	@Override
	public void appendHqlString(StringBuilder hql, SqmRenderContext context) {
		wrappedExpression.appendHqlString( hql, context );
	}

	@Override
	public <X> X accept(SemanticQueryWalker<X> walker) {
		return wrappedExpression.accept( walker );
	}

	@Override

View on GitHub (pinned to fad1729dce)

Solutions

  1. Re-express as numeric: cb.max(cb.selectCase().when(cb.isTrue(flag), 0).otherwise(1)) yields the 'min boolean' information in numeric form.
  2. Use cb.sum(...) to count true rows per group instead of min/max.
  3. Aggregate at the SQL level via native query where the dialect supports boolean min/max.
  4. Guard aggregation helpers with a numeric type check before calling min().

Example fix

// before
SqmBooleanExpression flag = (SqmBooleanExpression) cb.wrapExpressionAsBoolean(root.get("active"));
query.select(flag.min()); // UnsupportedOperationException
// after
query.select(cb.max(cb.selectCase().when(cb.isTrue(root.get("active")), 0).otherwise(1)));
Defensive patterns

Strategy: type-guard

Validate before calling

static boolean numeric(Expression<?> e) {
    return e.getJavaType() != null && Number.class.isAssignableFrom(e.getJavaType());
}
// wrapped boolean expressions: skip min(); use a case encoding instead

Type guard

static boolean aggregatableByMinMax(Expression<?> e) {
    Class<?> jt = e.getJavaType();
    return jt != null && Number.class.isAssignableFrom(jt);
}

Prevention

When it happens

Trigger: cb.wrapExpressionAsBoolean(...).min(), or .min() on SqmBooleanExpression results of nullif/coalesce over boolean paths in Hibernate 6 criteria.

Common situations: Report queries rolling up boolean flags; fluent builders that wrap boolean expressions then chain aggregates; codebases moving from HQL string min(boolean) attempts to typed criteria.

Related errors


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