{"record":{"id":"e15c359a5949972b","repo":"hibernate/hibernate-orm","slug":"the-from-clause-of-a-subquery-has-a-fetch-join","errorCode":null,"errorMessage":"The 'from' clause of a subquery has a 'fetch' join","messagePattern":"The 'from' clause of a subquery has a 'fetch' join","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java","lineNumber":2355,"sourceCode":"\t\t}\n\t\telse {\n\t\t\tthrow new ParsingException( \"unexpected join type\" );\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <X> SqmJoin<X, ?> getJoin(\n\t\t\tSqmRoot<X> sqmRoot,\n\t\t\tSqmJoinType joinType,\n\t\t\tHqlParser.JoinTargetContext joinTargetContext,\n\t\t\tString alias,\n\t\t\tboolean fetch) {\n\t\tif ( joinTargetContext instanceof HqlParser.JoinPathContext joinPathContext ) {\n\t\t\treturn (SqmJoin<X, ?>) joinPathContext.path().accept( this );\n\t\t}\n\t\telse if ( joinTargetContext instanceof HqlParser.JoinSubqueryContext joinSubqueryContext ) {\n\t\t\tif ( fetch ) {\n\t\t\t\tthrow new SemanticException( \"The 'from' clause of a subquery has a 'fetch' join\", query );\n\t\t\t}\n\t\t\tif ( getCreationOptions().useStrictJpaCompliance() ) {\n\t\t\t\tthrow new StrictJpaComplianceViolation(\n\t\t\t\t\t\t\"The JPA specification does not support subqueries in the from clause. \" +\n\t\t\t\t\t\t\t\t\"Please disable the JPA query compliance if you want to use this feature.\",\n\t\t\t\t\t\tStrictJpaComplianceViolation.Type.FROM_SUBQUERY\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfinal boolean lateral = joinSubqueryContext.LATERAL() != null;\n\t\t\tfinal var identifierConsumer = dotIdentifierConsumerStack.pop();\n\t\t\tfinal var subQuery = (SqmSubQuery<X>) joinSubqueryContext.subquery().accept( this );\n\t\t\tdotIdentifierConsumerStack.push( identifierConsumer );\n\t\t\tfinal var join = new SqmDerivedJoin<>( subQuery, alias, joinType, lateral, sqmRoot );\n\t\t\tprocessingStateStack.getCurrent().getPathRegistry().register( join );\n\t\t\treturn join;\n\t\t}\n\t\telse if ( joinTargetContext instanceof HqlParser.JoinFunctionContext joinFunctionContext ) {","sourceCodeStart":2337,"sourceCodeEnd":2373,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java#L2337-L2373","documentation":"In getJoin, the join target is a subquery (JoinSubqueryContext - e.g. 'join lateral (select ...) s') and the join was marked 'fetch'. A derived join over a subquery result is not a managed association, so there is nothing to fetch; Hibernate throws SemanticException.","triggerScenarios":"'select e from Employee e join fetch lateral (select ...) s on ...'; any 'join fetch' whose target is a (lateral) subquery in the from clause.","commonSituations":"Copy-pasting 'fetch' onto lateral joins adopted with Hibernate 6.6+; assuming fetch works uniformly on every join kind.","solutions":["Remove the 'fetch' keyword from the subquery join: 'join lateral (select ...) s'","Fetch only real, mapped associations of your roots"],"exampleFix":"// before\nselect e from Employee e join fetch lateral (select i from Item i where i.emp = e) s\n\n// after\nselect e from Employee e join lateral (select i from Item i where i.emp = e) s","handlingStrategy":"validation","validationCode":"// Reject 'join fetch lateral (select ...)' style constructs before execution\nstatic boolean fetchOnSubqueryJoin(String hql) {\n    return java.util.regex.Pattern.compile(\"join\\\\s+fetch\\\\s+(lateral\\\\s*)?\\\\(\", java.util.regex.Pattern.CASE_INSENSITIVE).matcher(hql).find();\n}\nif (fetchOnSubqueryJoin(hql)) throw new IllegalArgumentException(\"'fetch' is not valid on joins targeting a subquery\");","typeGuard":null,"tryCatchPattern":"try {\n    return em.createQuery(hql, Employee.class).getResultList();\n} catch (org.hibernate.query.sqm.SemanticException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"'fetch' join\")) {\n        throw new IllegalArgumentException(\"Remove 'fetch' from the (lateral) subquery join\", e);\n    }\n    throw e;\n}","preventionTips":["Apply 'fetch' only to mapped associations, never to derived/lateral subquery joins","When introducing lateral joins (Hibernate 6.6+), review every join for stale fetch keywords"],"tags":["hql","fetch-join","lateral-join","subquery","hibernate"],"backgroundTag":"fetch-join-in-subquery","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}