{"record":{"id":"4f8e20c20000504d","repo":"hibernate/hibernate-orm","slug":"access-to-from-node-from-getcorrelationparent","errorCode":null,"errorMessage":"Access to from node '\" + from.getCorrelationParent() + \"' is not possible in from-clause subqueries, unless the 'lateral' keyword is used for the subquery!","messagePattern":"Access to from node '\" \\+ from\\.getCorrelationParent\\(\\) \\+ \"' is not possible in from-clause subqueries, unless the 'lateral' keyword is used for the subquery!","errorType":"exception","errorClass":"InterpretationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java","lineNumber":2921,"sourceCode":"\t\t\t// If we have just inner joins against a correlated root, we can render the joins as references\n\t\t\t// If we correlate a join, we have to create a special SqmRoot shell called SqmCorrelatedRootJoin.\n\t\t\t// The only purpose of that is to serve as SqmRoot, which is needed for the FROM clause.\n\t\t\t// It will always contain just a single correlated join though, which is what is actually correlated\n\t\t\tfinal SqmFrom<?, ?> from;\n\t\t\tif ( sqmRoot instanceof SqmCorrelatedRootJoin<?> ) {\n\t\t\t\tfinal var sqmJoins = sqmRoot.getSqmJoins();\n\t\t\t\tassert sqmJoins.size() == 1\n\t\t\t\t\t&& sqmJoins.get( 0 ).isCorrelated();\n\t\t\t\tfrom = sqmJoins.get( 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfrom = sqmRoot;\n\t\t\t}\n\t\t\tfinal var parentTableGroup = fromClauseIndex.findTableGroup(\n\t\t\t\t\tfrom.getCorrelationParent().getNavigablePath()\n\t\t\t);\n\t\t\tif ( parentTableGroup == null ) {\n\t\t\t\tthrow new InterpretationException( \"Access to from node '\" + from.getCorrelationParent() + \"' is not possible in from-clause subqueries, unless the 'lateral' keyword is used for the subquery!\" );\n\t\t\t}\n\t\t\tfinal var sqlAliasBase = sqlAliasBaseManager.createSqlAliasBase( parentTableGroup.getGroupAlias() );\n\t\t\tif ( parentTableGroup instanceof PluralTableGroup pluralTableGroup ) {\n\t\t\t\tfinal var correlatedPluralTableGroup = new CorrelatedPluralTableGroup(\n\t\t\t\t\t\tparentTableGroup,\n\t\t\t\t\t\tsqlAliasBase,\n\t\t\t\t\t\tcurrentQuerySpec,\n\t\t\t\t\t\tpredicate -> additionalRestrictions = combinePredicates( additionalRestrictions, predicate ),\n\t\t\t\t\t\tsessionFactory\n\t\t\t\t);\n\t\t\t\tfinal var elementTableGroup = pluralTableGroup.getElementTableGroup();\n\t\t\t\tif ( elementTableGroup != null ) {\n\t\t\t\t\tfinal var correlatedElementTableGroup = new CorrelatedTableGroup(\n\t\t\t\t\t\t\telementTableGroup,\n\t\t\t\t\t\t\tsqlAliasBase,\n\t\t\t\t\t\t\tcurrentQuerySpec,\n\t\t\t\t\t\t\tpredicate -> additionalRestrictions = combinePredicates( additionalRestrictions, predicate ),\n\t\t\t\t\t\t\tsessionFactory","sourceCodeStart":2903,"sourceCodeEnd":2939,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java#L2903-L2939","documentation":"Thrown while translating a from-clause subquery (derived table). The subquery references the correlation parent of one of its SqmFrom nodes, but fromClauseIndex.findTableGroup() cannot find a table group for that parent's navigable path. Standard SQL forbids a derived table from seeing outer-query aliases unless the join is declared LATERAL, so Hibernate refuses to translate it.","triggerScenarios":"HQL like 'select ... from A a join (select ... from B b where b.aId = a.id) d' - the derived table body references outer alias 'a' without the lateral keyword; criteria code using SqmSubQuery in the from clause with a correlation to the outer query but without marking the derived join lateral.","commonSituations":"Porting native SQL or JPQL queries that used correlated derived tables; Hibernate 6+ where HQL gained full subquery support and users try correlated from-clause subqueries for the first time; upgrading applications that previously fell back to native SQL.","solutions":["Mark the derived join as lateral: 'left join lateral (select ...) alias on ...' so the subquery may reference outer aliases","Move the correlation predicate out of the subquery (uncorrelate it) and correlate via the outer where-clause instead","Replace the from-clause subquery with a scalar subquery in the select or where clause, which may correlate freely","Fall back to a native SQL query if the dialect lacks lateral support"],"exampleFix":"// before\nselect p.id, c.total\nfrom Person p,\n     (select sum(o.amount) as total from Ord o where o.personId = p.id) c\n\n// after\nselect p.id, c.total\nfrom Person p\nleft join lateral (select sum(o.amount) as total from Ord o where o.personId = p.id) c","handlingStrategy":"validation","validationCode":"// Reject derived tables that reference an outer alias without 'lateral' before running\nboolean derivedReferencesOuter = hql.matches(\"(?is).*\\\\bjoin\\\\s*\\\\((.*?)\\\\).*\")\n    && referencesOuterAlias(hql); // custom check: alias from outer from-clause appears inside the (...) block\nif (derivedReferencesOuter && !hql.toLowerCase().contains(\"lateral\")) {\n    throw new IllegalArgumentException(\"Derived subquery correlates to outer alias; use 'join lateral' or a native query\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql).getResultList();\n} catch (org.hibernate.query.sqm.InterpretationException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"lateral\")) {\n        return runNativeFallback(hql); // pre-approved native variant of the same query\n    }\n    throw e;\n}","preventionTips":["Write correlated from-clause subqueries as 'left join lateral (...)' from the start","Prefer correlated scalar subqueries in select/where over derived tables when porting SQL","Add HQL smoke tests for every ported native query so this fails in CI, not production"],"tags":["hibernate","hql","lateral","derived-table","correlated-subquery"],"backgroundTag":"lateral-join-required","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}