{"record":{"id":"fffb6f4328b8c20d","repo":"hibernate/hibernate-orm","slug":"can-t-set-alias-on-a-correlated-root","errorCode":null,"errorMessage":"Can't set alias on a correlated root","messagePattern":"Can't set alias on a correlated root","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmCorrelatedRoot.java","lineNumber":72,"sourceCode":"\t@Nonnull\n\t@Override\n\tpublic SqmRoot<T> getCorrelationParent() {\n\t\treturn correlationParent;\n\t}\n\n\t@Override\n\tpublic SqmPath<T> getWrappedPath() {\n\t\treturn getCorrelationParent();\n\t}\n\n\t@Override\n\tpublic @Nullable String getExplicitAlias() {\n\t\treturn correlationParent.getExplicitAlias();\n\t}\n\n\t@Override\n\tpublic void setExplicitAlias(@Nullable String explicitAlias) {\n\t\tthrow new UnsupportedOperationException( \"Can't set alias on a correlated root\" );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic JpaSelection<T> alias(@Nonnull String name) {\n\t\tsetAlias( name );\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic boolean isCorrelated() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic SqmRoot<T> getCorrelatedRoot() {\n\t\treturn this;\n\t}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmCorrelatedRoot.java#L54-L90","documentation":"SqmCorrelatedRoot.setExplicitAlias throws UnsupportedOperationException because a correlated root does not own its alias: getExplicitAlias() delegates to the outer correlation parent, so mutating the alias on the inner copy would desynchronize the correlation. JPA's Root.alias(String) funnels into setExplicitAlias, so calling alias() on the root returned by Subquery.correlate(...) triggers this immediately. The alias must be managed on the outer parent root.","triggerScenarios":"Criteria code doing Root<X> r = subquery.correlate(root); r.alias(\"x\"); any framework that unconditionally aliases every root it touches, including correlated ones; SqmCorrelatedRoot.alias(name) calls in HQL-building helpers that mirror outer aliasing onto the correlation.","commonSituations":"Specification/query-builder libraries that assign generated aliases to all roots for deterministic SQL; code copied from a main query where aliasing roots is fine, reused inside an exists() subquery; upgrading Hibernate versions where alias handling of correlated roots became strict (previously ignored or tolerated).","solutions":["Set the alias on the outer parent root before creating the correlation - the correlated root inherits it via getExplicitAlias().","Remove the alias() call on the correlated root; use the existing parent alias when referencing the path inside the subquery.","In generic code, check root.isCorrelated() (true for SqmCorrelatedRoot) before calling alias()/setAlias().","Where a distinct inner alias is required, correlate via a join or restructure the subquery select instead."],"exampleFix":"// before - aliasing the correlated root throws\nRoot<Employee> correlated = subQuery.correlate(outerRoot);\ncorrelated.alias(\"e2\");\n\n// after - alias the outer root first; the correlation reuses it\nouterRoot.alias(\"e\");\nRoot<Employee> correlated = subQuery.correlate(outerRoot);\n// reference correlated.get(\"salary\") - no extra alias needed","handlingStrategy":"type-guard","validationCode":"// Alias the outer root BEFORE correlating; correlated roots must not be aliased\nif (!outerRoot.isCorrelated()) {\n    outerRoot.alias(\"e\");\n}\nRoot<Employee> correlated = subQuery.correlate(outerRoot); // inherits alias from parent","typeGuard":"static boolean aliasMutable(org.hibernate.query.criteria.JpaFrom<?, ?> from) {\n    return !from.isCorrelated(); // SqmCorrelatedRoot.isCorrelated() == true and forbids setExplicitAlias\n}","tryCatchPattern":"try {\n    root.alias(name);\n} catch (UnsupportedOperationException e) {\n    // correlated root: alias lives on the correlation parent - nothing to do\n}","preventionTips":["Alias roots at creation time in the outer query, before any correlate() call.","Check isCorrelated() before aliasing any root in shared criteria utilities.","Do not copy outer-query aliasing loops into exists/subquery builders.","Reference correlated paths via their inherited parent alias."],"tags":["hibernate","sqm","criteria-api","correlation","subquery","alias"],"backgroundTag":"correlated-root-alias","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}