hibernate/hibernate-orm · error · IllegalStateException
Not a compound selection
Error message
Not a compound selection
What it means
AbstractJpaSelection.getSelectionItems throws IllegalStateException when called on a selection that is not a compound selection. In the JPA Criteria API getSelectionItems() is only meaningful for selections built via multiselect()/tuple/array/construct builders that aggregate several items; the base implementation in Hibernate returns isCompoundSelection()==false and treats getSelectionItems() as an illegal call. Subclasses that are compound (e.g. SqmJpaCompoundSelection) override both methods.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/jpa/AbstractJpaSelection.java:43
protected AbstractJpaSelection(@Nullable SqmBindableType<? super T> sqmExpressible, NodeBuilder criteriaBuilder) {
super( sqmExpressible, criteriaBuilder );
}
@Nonnull
@Override
public JpaSelection<T> alias(@Nonnull String alias) {
setAlias( alias );
return this;
}
@Override
public boolean isCompoundSelection() {
return false;
}
@Override
public List<? extends JpaSelection<?>> getSelectionItems() {
throw new IllegalStateException( "Not a compound selection" );
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Guard with `if (selection.isCompoundSelection())` and treat non-compound as a single item
- Use `List.of(selection)` for the non-compound branch so downstream code sees a uniform list
- For explicit multi-item selections use cb.tuple()/cb.array()/cb.construct(...) or query.multiselect(...) so the compound implementation is used
- In tree-walkers, recurse via instanceof checks on SqmExpression subtypes rather than assuming getSelectionItems exists
Example fix
// before
List<? extends JpaSelection<?>> items = query.getSelection().getSelectionItems(); // IllegalStateException for single select
// after
JpaSelection<?> sel = query.getSelection();
List<? extends JpaSelection<?>> items = sel.isCompoundSelection()
? sel.getSelectionItems()
: List.of( sel ); Defensive patterns
Strategy: type-guard
Validate before calling
if (selection.isCompoundSelection()) {
items = selection.getSelectionItems();
} else {
items = List.of(selection);
} Type guard
static List<? extends jakarta.persistence.criteria.Selection<?>> itemsOf(
jakarta.persistence.criteria.Selection<?> s) {
return s.isCompoundSelection() ? s.getSelectionItems() : List.of(s);
} Prevention
- Always pair getSelectionItems() with an isCompoundSelection() check
- Use multiselect()/tuple()/array() when you need a guaranteed compound selection
- Write one itemsOf() utility and use it everywhere in selection-walking code
When it happens
Trigger: Calling `selection.getSelectionItems()` on a plain expression/path (a single SqmPath, literal, parameter, function result); generic result-mapping code that iterates `query.getSelection().getSelectionItems()` for both single and multi selects; transformers that flatten selection trees without checking isCompoundSelection first.
Common situations: DTO-projection frameworks that walk the criteria selection tree to derive column aliases/types; code that worked against multiselect queries breaking the first time it receives a single-item selection; migrating hand-rolled HQL result mapping to criteria where the selection is one expression.
Related errors
- JPA selection is not compound
- Blobs may not be accessed after serialization
- Clobs may not be accessed after serialization
- Unknown entity type '{}'
- Same column is added more than once with different values fo
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/7530c422f661c1ce.
Report an issue: GitHub.