{"record":{"id":"bbd580f192e6c00b","repo":"hibernate/hibernate-orm","slug":"multiple-from-elements-expose-unqualified-attribut","errorCode":null,"errorMessage":"Multiple from elements expose unqualified attribute: ${identifierText}","messagePattern":"Multiple from elements expose unqualified attribute: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java","lineNumber":1666,"sourceCode":"\t\t\t\t// If the current query part is a query group, check if the text matches\n\t\t\t\t// an attribute name of one of the selected SqmFrom elements or the path source name of a SqmPath\n\t\t\t\tSqmFrom<?, ?> found = null;\n\t\t\t\tint sqmPosition = 0;\n\t\t\t\tfinal var selections = queryPart.getFirstQuerySpec().getSelectClause().getSelections();\n\t\t\t\tfor ( int i = 0; i < selections.size(); i++ ) {\n\t\t\t\t\tfinal var sqmSelection = selections.get( i );\n\t\t\t\t\tif ( identifierText.equals( sqmSelection.getAlias() ) ) {\n\t\t\t\t\t\treturn new SqmAliasedNodeRef(\n\t\t\t\t\t\t\t\ti + 1,\n\t\t\t\t\t\t\t\tnodeBuilder.getIntegerType(),\n\t\t\t\t\t\t\t\tnodeBuilder\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tfinal var selectableNode = sqmSelection.getSelectableNode();\n\t\t\t\t\tif ( selectableNode instanceof SqmFrom<?, ?> fromElement ) {\n\t\t\t\t\t\tif ( fromElement.getReferencedPathSource().findSubPathSource( identifierText ) != null ) {\n\t\t\t\t\t\t\tif ( sqmPosition != 0 ) {\n\t\t\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\t\t\"Multiple from elements expose unqualified attribute: \" + identifierText );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfound = fromElement;\n\t\t\t\t\t\t\tsqmPosition = i + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if ( selectableNode instanceof SqmPath<?> path ) {\n\t\t\t\t\t\tif ( identifierText.equals( path.getReferencedPathSource().getPathName() ) ) {\n\t\t\t\t\t\t\tif ( sqmPosition != 0 ) {\n\t\t\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\t\t\"Multiple from elements expose unqualified attribute: \" + identifierText );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsqmPosition = i + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif ( found != null ) {\n\t\t\t\t\treturn new SqmAliasedNodeRef(","sourceCodeStart":1648,"sourceCodeEnd":1684,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java#L1648-L1684","documentation":"Thrown while resolving an unqualified identifier in group-by/order-by against the select list: the identifier names a sub-path source exposed by a select item that is an SqmFrom, and a second from-element select item exposes the same attribute name. The first match records sqmPosition; the second match finds sqmPosition != 0 and throws IllegalStateException because the positional reference would be ambiguous.","triggerScenarios":"'select e, d from Employee e join Department d ... group by name' where both e and d expose an attribute 'name'; any unqualified group-by identifier resolvable through two or more from-elements appearing in the select list.","commonSituations":"Entities sharing attribute names (id, name, version, code); queries selecting multiple roots or joins and grouping by a bare column name; refactors that add a second from-element with a colliding attribute name.","solutions":["Qualify the identifier with the from-alias: 'group by e.name'","Give the select expression an alias and group by that alias","Restructure the select list so only one candidate from-element exposes the attribute"],"exampleFix":"// before\nselect e, d from Employee e join e.department d group by name\n\n// after\nselect e, d from Employee e join e.department d group by e.name","handlingStrategy":"validation","validationCode":"static boolean uniqueAttributeExposure(EntityManagerFactory emf, String hqlEntity, String attr, List<String> otherAliases) {\n    // conservative check: ensure the unqualified attribute exists on exactly one from-element type\n    var metamodel = emf.getMetamodel();\n    long matches = otherAliases.stream().filter(a -> {\n        try {\n            var attrFound = metamodel.entity(a).getAttribute(attr) != null;\n            return attrFound;\n        } catch (IllegalArgumentException unknown) {\n            return false;\n        }\n    }).count();\n    return matches <= 1;\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql, Object[].class).list();\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Multiple from elements expose unqualified attribute\")) {\n        throw new IllegalArgumentException(\"Ambiguous group-by attribute - qualify it with an alias: \" + hql, e);\n    }\n    throw e;\n}","preventionTips":["Always qualify group-by/order-by attributes with their from-alias ('group by e.name')","Alias every select item so grouping can target unambiguous aliases","Watch for common attribute names (id, name, version) when joining multiple roots"],"tags":["hql","group-by","ambiguous-column","hibernate"],"backgroundTag":"ambiguous-column-reference","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}