hibernate/hibernate-orm · error · UnsupportedOperationException

Boolean expression does not support max()

Error message

Boolean expression does not support max()

What it means

SqmBooleanExpressionWrapper adapts an arbitrary SQM expression to the Boolean expression API (e.g. results of nodeBuilder().wrapExpressionAsBoolean or boolean-producing operations). Its max() throws UnsupportedOperationException('Boolean expression does not support max()') because Boolean aggregation is not representable in the SQM type system.

Source

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

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

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

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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Aggregate a numeric encoding instead: wrap the aggregate, not the boolean — cb.max(cb.selectCase().when(cb.isTrue(wrapped), 1).otherwise(0)).
  2. Use cb.sum over the case encoding when you need a count of true values.
  3. Perform the rollup in native SQL if the dialect supports boolean aggregates.
  4. Keep a type check in generic aggregation code: skip max()/min() for Boolean-typed expressions.

Example fix

// before
SqmBooleanExpression flag = (SqmBooleanExpression) cb.wrapExpressionAsBoolean(root.get("active"));
query.select(flag.max()); // UnsupportedOperationException
// after
query.select(cb.sum(cb.selectCase().when(cb.isTrue(root.get("active")), 1).otherwise(0)));
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 max(); aggregate a case-to-int projection instead

Type guard

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

Prevention

When it happens

Trigger: Calling .max() on an expression wrapped into the Boolean API: cb.wrapExpressionAsBoolean(expr).max(), or operations that return SqmBooleanExpression (nullif/Coalesce over booleans) followed by .max().

Common situations: Fluent criteria pipelines that wrap then aggregate; aggregation helpers receiving already-wrapped boolean expressions; queries generating per-group boolean rollups.

Related errors


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