hibernate/hibernate-orm · error · IllegalArgumentException
empty selections passed to criteria query typed as Object
Error message
empty selections passed to criteria query typed as Object
What it means
When a criteria (sub)query has result type Object, SqmSubQuery.getResultSelection decides the selection purely from the size of the list passed to multiselect(List): one item becomes that item, several become an array. With zero selections there is nothing to render in the SELECT clause, so Hibernate throws IllegalArgumentException rather than generating invalid SQL. In practice this means multiselect was called with an empty list, or select() was never invoked before execution.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/select/SqmSubQuery.java:295
public SqmSubQuery<T> multiselect(Selection<?>... selections) {
validateComplianceMultiselect();
final Selection<? extends T> resultSelection = getResultSelection( selections );
getQuerySpec().setSelection( (JpaSelection<T>) resultSelection );
return this;
}
@Override
public SqmSubQuery<T> multiselect(List<Selection<?>> selectionList) {
validateComplianceMultiselect();
getQuerySpec().setSelection( getResultSelection( selectionList ) );
return this;
}
private JpaSelection<T> getResultSelection(List<Selection<?>> selections) {
final Class<T> resultType = getResultType();
if ( resultType == Object.class ) {
final JpaSelection<?> selection = switch ( selections.size() ) {
case 0 -> throw new IllegalArgumentException(
"empty selections passed to criteria query typed as Object" );
case 1 -> (JpaSelection<?>) selections.get( 0 );
default -> nodeBuilder().array( selections );
};
//noinspection unchecked
return (JpaSelection<T>) selection;
}
else if ( Tuple.class.isAssignableFrom( resultType ) ) {
//noinspection unchecked
return (JpaSelection<T>) nodeBuilder().tuple( selections );
}
else if ( resultType.isArray() ) {
return nodeBuilder().array( resultType, selections );
}
else {
return nodeBuilder().construct( resultType, selections );
}
}View on GitHub (pinned to fad1729dce)
Solutions
- Ensure the subquery gets exactly one selection before execution: call subquery.select(expression) instead of multiselect when a single value is expected
- Guard dynamic builders: if the selection list is empty, throw your own descriptive exception or skip executing the query
- Give the subquery a concrete result type (Long, String, Tuple) so mistakes surface earlier
Example fix
// before
List<Selection<?>> empty = List.of();
sub.multiselect(empty); // IllegalArgumentException at getResultSelection
// after
if (selections.isEmpty()) {
throw new IllegalStateException("Subquery requires at least one selection");
}
sub.multiselect(selections); Defensive patterns
Strategy: validation
Validate before calling
if (selections == null || selections.isEmpty()) {
throw new IllegalStateException("Refusing to build subquery with empty selection");
}
sub.multiselect(selections); Try / catch
try { sub.multiselect(list); } catch (IllegalArgumentException e) { if (e.getMessage().contains("empty selections")) { /* log and skip query or default to select(cb.literal(1)) */ } else throw e; } Prevention
- In dynamic builders, always end with exactly one select()/multiselect() call and assert the list is non-empty
- Prefer subquery.select(singleExpression) when the result type is Object
- Unit-test dynamic query builders with empty filter inputs
When it happens
Trigger: query.subquery(Object.class) followed by subquery.multiselect(Collections.emptyList()) or List.of(); dynamic query builders that always call multiselect() and pass a computed list that ends up empty; refactors that drop the select() call.
Common situations: Dynamic-filter APIs where the selection list is assembled from user input or conditionals and can legitimately be empty; generic projection frameworks that wrap every criteria in multiselect without checking.
Related errors
- Selection item in a multi-select cannot contain compound arr
- DELETE query cannot be sub-query
- Not correlated
- The JPA specification does not support subqueries in the fro
- Correlated derived root does not have an entity type. Use ge
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c5c18b533af9581b.
Report an issue: GitHub.