{"record":{"id":"949d7e331f7b64a4","repo":"hibernate/hibernate-orm","slug":"subquery-parent-of-all-operands-must-match","errorCode":null,"errorMessage":"Subquery parent of all operands must match","messagePattern":"Subquery parent of all operands must match","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java","lineNumber":798,"sourceCode":"\t\t);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> JpaSubQuery<T> setOperation(\n\t\t\tSetOperator operator,\n\t\t\tSubquery<? extends T> subquery,\n\t\t\tSubquery<?>... queries) {\n\t\tfinal var resultType = (Class<T>) subquery.getResultType();\n\t\tfinal var parent = (SqmQuery<T>) subquery.getParent();\n\t\tfinal List<SqmQueryPart<T>> queryParts = new ArrayList<>( queries.length + 1 );\n\t\tfinal Map<String, SqmCteStatement<?>> cteStatements = new LinkedHashMap<>();\n\t\tcollectQueryPartsAndCtes( (SqmSelectQuery<T>) subquery, queryParts, cteStatements );\n\t\tfor ( var query : queries ) {\n\t\t\tif ( query.getResultType() != resultType ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Result type of all operands must match\" );\n\t\t\t}\n\t\t\tif ( query.getParent() != parent ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Subquery parent of all operands must match\" );\n\t\t\t}\n\t\t\tcollectQueryPartsAndCtes( (SqmSelectQuery<T>) query, queryParts, cteStatements );\n\t\t}\n\t\treturn new SqmSubQuery<>(\n\t\t\t\tparent,\n\t\t\t\tnew SqmQueryGroup<>( this, operator, queryParts ),\n\t\t\t\tresultType,\n\t\t\t\tcteStatements,\n\t\t\t\tthis\n\t\t);\n\t}\n\n\tprivate <T> void collectQueryPartsAndCtes(\n\t\t\tSqmSelectQuery<T> query,\n\t\t\tList<SqmQueryPart<T>> queryParts,\n\t\t\tMap<String, SqmCteStatement<?>> cteStatements) {\n\t\tqueryParts.add( query.getQueryPart() );\n\t\tfor ( var cteStatement : query.getCteStatements() ) {","sourceCodeStart":780,"sourceCodeEnd":816,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java#L780-L816","documentation":"When applying a set operation to subqueries, Hibernate requires all operands to belong to the same enclosing query: query.getParent() must be reference-equal for every operand. A subquery is scoped to the AbstractQuery it was created from, and mixing subqueries from different parents (or from a different level of the tree) produces an SqmQueryGroup whose parts Hibernate cannot legally attach, so it fails fast with IllegalArgumentException.","triggerScenarios":"cb.union(subA, subB) where subA = outerQuery.subquery(X.class) and subB = otherQuery.subquery(X.class) (two different CriteriaQuery instances); a subquery created from a subquery (nested scope) unioned with one created from the top-level query; reusing a cached/helper subquery in a new query.","commonSituations":"Utility methods that build reusable subqueries parameterized by an outer query, then called with two different outers; refactoring a query builder so helper subqueries are created against the wrong owner; copy-pasting subquery construction across query builders.","solutions":["Create all operand subqueries from the same enclosing query object: call query.subquery(...) once per operand on the identical AbstractQuery instance.","Pass the owning query into your subquery-building helpers so parents always match.","If operands conceptually belong to different queries, restructure: perform the set operation at the CriteriaQuery level instead of the Subquery level."],"exampleFix":"// before\nSubquery<Long> idsA = queryA.subquery(Long.class); // parent = queryA\nSubquery<Long> idsB = queryB.subquery(Long.class); // parent = queryB\ncb.union(idsA, idsB); // throws: Subquery parent of all operands must match\n\n// after\nSubquery<Long> idsA = query.subquery(Long.class); // both from the same 'query'\nSubquery<Long> idsB = query.subquery(Long.class);\ncb.union(idsA, idsB);","handlingStrategy":"validation","validationCode":"boolean sameParent(Subquery<?> first, Subquery<?>... rest) {\n    AbstractQuery<?> parent = first.getParent();\n    for (Subquery<?> s : rest) if (s.getParent() != parent) return false;\n    return true;\n}\nif (!sameParent(s1, s2)) throw new IllegalStateException(\"subquery operands belong to different queries\");","typeGuard":"static boolean sharesParent(Subquery<?> a, Subquery<?> b) {\n    return a.getParent() == b.getParent();\n}","tryCatchPattern":"try {\n    cb.union(s1, s2);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Subquery parent\")) { /* recreate both subqueries from the same owner */ }\n    else throw e;\n}","preventionTips":["Create operand subqueries inside the same method that owns the outer query so parents cannot diverge.","Pass the owning AbstractQuery into subquery-building helpers as a parameter.","Never cache Subquery instances for reuse across queries."],"tags":["hibernate","criteria","subquery","set-operations","query-scope"],"backgroundTag":"subquery-parent-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}