hibernate/hibernate-orm · error · SemanticException
Numeric literal '${position}' used in 'group by' does not ma
Error message
Numeric literal '${position}' used in 'group by' does not match a registered select item What it means
Thrown while Hibernate translates HQL: a positional reference in 'group by' (e.g. 'group by 2') was validated against the select list of the query part and no select item is registered at that 1-based position (nodeByPosition returned null). Hibernate must map the ordinal to an SqmAliasedNodeRef pointing at a real select item, so an out-of-range ordinal is a semantic error, not silently ignored.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java:1634
final var processingState = processingStateStack.getCurrent();
final var processingQuery = processingState.getProcessingQuery();
final var queryPart = sqmQueryPart( processingQuery );
if ( child instanceof TerminalNode ) {
if ( definedCollate ) {
// This is syntactically disallowed
throw new SyntaxException( "'collate' is not allowed for position based 'order by' or 'group by' items" );
}
else if ( !allowPositionalOrAliases ) {
// This is syntactically disallowed
throw new SyntaxException( "Position based 'order by' is not allowed in 'over' or 'within group' clauses" );
}
final int position = Integer.parseInt( child.getText() );
// make sure this selection exists
final var nodeByPosition = nodeByPosition( queryPart, position, processingState );
if ( nodeByPosition == null ) {
throw new SemanticException( "Numeric literal '" + position
+ "' used in 'group by' does not match a registered select item",
query );
}
return new SqmAliasedNodeRef(
position,
nodeBuilder.resolveExpressible( integerDomainType ),
nodeBuilder
);
}
else if ( child instanceof HqlParser.IdentifierContext identifierContext ) {
final String identifierText = visitIdentifier( identifierContext );
if ( queryPart instanceof SqmQueryGroup<?> ) {
// If the current query part is a query group, check if the text matches
// an attribute name of one of the selected SqmFrom elements or the path source name of a SqmPath
SqmFrom<?, ?> found = null;
int sqmPosition = 0;
final var selections = queryPart.getFirstQuerySpec().getSelectClause().getSelections();View on GitHub (pinned to fad1729dce)
Solutions
- Replace the ordinal with the actual expression or path: 'group by e.name'
- If keeping ordinals, verify 1 <= n <= number of select items in that query part (positions are 1-based) and fix the index
- Alias the select item and group by the alias instead of the position
- For dynamic queries, build the select list first and derive ordinals from it, or always group by full expressions
Example fix
// before select e.name, e.dept from Employee e group by 3 // after select e.name, e.dept from Employee e group by e.dept
Defensive patterns
Strategy: validation
Validate before calling
static boolean validGroupByOrdinal(String hql, int n) {
String lower = hql.toLowerCase();
int s = lower.indexOf("select") + 6;
int f = lower.indexOf(" from ");
if (s < 6 || f < 0 || f <= s) return false;
String list = hql.substring(s, f);
if (list.isBlank()) return false;
int depth = 0, count = 1;
for (char c : list.toCharArray()) {
if (c == '(') depth++;
else if (c == ')') depth--;
else if (c == ',' && depth == 0) count++;
}
return n >= 1 && n <= count;
}
// before: em.createQuery("select e.name from Employee e group by " + n)
if (!validGroupByOrdinal(hql, n)) throw new IllegalArgumentException("group-by ordinal out of range: " + n); Try / catch
try {
return session.createQuery(hql, Tuple.class).list();
} catch (org.hibernate.query.sqm.SemanticException e) {
// UnknownEntityException also lands here (subclass)
throw new IllegalArgumentException("HQL failed semantic validation: " + hql, e);
} Prevention
- Prefer grouping by explicit expressions or aliases over ordinals in HQL
- Treat ordinals as 1-based, and validate them against the select-list size when building queries dynamically
- Run a cheap createQuery() smoke test at startup or test time for every stored HQL string
When it happens
Trigger: HQL such as 'select e.name from Employee e group by 2' when only one select item exists; 'group by 0'; an ordinal greater than the select-list size; dynamically assembled queries where the 'group by N' was computed against a different select list (e.g. branches of a set operation with different select counts).
Common situations: Porting native SQL where GROUP BY 1 is legal into HQL; off-by-one mistakes from assuming 0-based positions; builders that append group-by ordinals before the select list is finalized.
Related errors
- Summarization is not supported by DBMS
- Summarization is not supported by DBMS
- Summarization is not supported by DBMS
- Summarization is not supported by DBMS
- Summarization is not supported by DBMS
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/46f53147f71c6ac8.
Report an issue: GitHub.