{"record":{"id":"93254f05dbe5c248","repo":"hibernate/hibernate-orm","slug":"jpa-selection-is-not-compound","errorCode":null,"errorMessage":"JPA selection is not compound","messagePattern":"JPA selection is not compound","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/select/SqmSubQuery.java","lineNumber":336,"sourceCode":"\t\treturn (SqmExpression<T>) super.getSelection();\n\t}\n\n\t@Override\n\tpublic boolean isCompoundSelection() {\n\t\t// A subquery is always a single/scalar expression, so it can't be a compound selection\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic List<? extends JpaSelection<?>> getSelectionItems() {\n\t\treturn Collections.emptyList();\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic List<Selection<?>> getCompoundSelectionItems() {\n\t\t// A subquery is always a single/scalar expression, so it can't be a compound selection\n\t\tthrow new IllegalStateException( \"JPA selection is not compound\" );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic SqmSubQuery<T> distinct(boolean distinct) {\n\t\tsuper.distinct( distinct );\n\t\treturn this;\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic SqmSubQuery<T> where(@Nonnull Expression<Boolean> restriction) {\n\t\tsuper.where( restriction );\n\t\treturn this;\n\t}\n\n\t@Nonnull\n\t@Override","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/select/SqmSubQuery.java#L318-L354","documentation":"getCompoundSelectionItems() is only meaningful for compound (multi-item) selections such as multiselect/array/tuple constructions. SqmSubQuery.isCompoundSelection() returns false — a subquery is always a single scalar expression — so calling getCompoundSelectionItems() on a subquery throws IllegalStateException. Code that processes arbitrary Selection trees must branch on isCompoundSelection() first.","triggerScenarios":"Generic result-mapping utilities, tuple transformers, or criteria walkers that unconditionally call getCompoundSelectionItems() (or cast Selection to CompoundSelection) on every node, encountering a Selection that is actually a Subquery.","commonSituations":"In-house criteria-to-SQL/DTO mappers; libraries that emulate Spring Data projections over JPA criteria; code migrated from a query type that was compound to one where a subquery now appears in the selection list.","solutions":["Check selection.isCompoundSelection() before calling getCompoundSelectionItems() and treat false as 'single expression'","For subqueries, use getSelectionItems() (which returns an empty list for SqmSubQuery) or simply handle the subquery as one atomic item","Reorder the mapper to switch on the concrete JpaSelection subtype instead of assuming compound"],"exampleFix":"// before\nfor (Selection<?> s : query.getSelectionList()) {\n    ((CompoundSelection<?>) s).getCompoundSelectionItems(); // IllegalStateException when s is a subquery\n}\n\n// after\nfor (Selection<?> s : query.getSelectionList()) {\n    if (s.isCompoundSelection()) {\n        ((CompoundSelection<?>) s).getCompoundSelectionItems();\n    } else {\n        handleSingleExpression(s); // subquery lands here\n    }\n}","handlingStrategy":"type-guard","validationCode":"if (selection.isCompoundSelection()) { items = selection.getCompoundSelectionItems(); } else { /* single expression, possibly a subquery */ }","typeGuard":"static boolean isCompound(Selection<?> s) { return s.isCompoundSelection(); } // false for SqmSubQuery","tryCatchPattern":"try { items = sel.getCompoundSelectionItems(); } catch (IllegalStateException e) { if (e.getMessage().contains(\"not compound\")) items = List.of(sel); else throw e; }","preventionTips":["Never cast Selection to CompoundSelection without checking isCompoundSelection() first","Treat subqueries as atomic single expressions in result mappers","Add a subquery to the selection in tests of generic mapping utilities"],"tags":["hibernate","criteria-api","selection","subquery","sqm"],"backgroundTag":"non-compound-selection-access","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}