hibernate/hibernate-orm · error · SemanticException
Composite query parameter cannot be used in select
Error message
Composite query parameter cannot be used in select
What it means
When a query parameter's resolved SQL expression is an SqlTuple (multiple columns - an embeddable, composite user type, or composite/embeddedId key), it cannot be projected as a single select item: JDBC has no single binding for a tuple in the select list. SqmParameterInterpretation.createDomainResult therefore throws SemanticException('Composite query parameter cannot be used in select') at SQL-AST creation time. The query fails at creation, never at execution.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqmParameterInterpretation.java:87
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
getResolvedExpression().accept( sqlTreeWalker );
}
@Override
public MappingModelExpressible<?> getExpressionType() {
return valueMapping;
}
@Override
public DomainResult<?> createDomainResult(
String resultVariable,
DomainResultCreationState creationState) {
final var resolvedExpression = getResolvedExpression();
if ( resolvedExpression instanceof SqlTuple ) {
throw new SemanticException( "Composite query parameter cannot be used in select" );
}
final var jdbcMapping = resolvedExpression.getExpressionType().getSingleJdbcMapping();
final var sqlAstCreationState = creationState.getSqlAstCreationState();
final var sqlSelection =
sqlAstCreationState.getSqlExpressionResolver()
.resolveSqlSelection(
resolvedExpression,
jdbcMapping.getJdbcJavaType(),
null,
sqlAstCreationState.getCreationContext().getTypeConfiguration()
);
return new BasicResult(
sqlSelection.getValuesArrayPosition(),
resultVariable,
jdbcMapping.getMappedJavaType(),
jdbcMapping.getValueConverter(),
null,View on GitHub (pinned to fad1729dce)
Solutions
- Select the component attributes explicitly: 'select :empId.part1, :empId.part2 ...' is not supported either - instead select the entity's own components 'select e.id.a, e.id.b' and bind the parameter only in WHERE
- Bind the composite parameter only in comparison predicates (where e.id = :empId), never in SELECT or ORDER BY
- If you need the value back, return it from Java: query the where clause with the parameter and prepend the bound value client-side
- Avoid parameters as select items entirely - use literals or entity attributes in the select list
Example fix
-- before select :deptPk from Department d where d.pk = :deptPk -- deptPk is @EmbeddedId -- after select d.pk.code, d.pk.region from Department d where d.pk = :deptPk
Defensive patterns
Strategy: validation
Validate before calling
// Reject composite parameters before query creation if they appear as select items
if (paramValue != null && em.getMetamodel() instanceof MetamodelImpl) {
Class<?> pc = paramValue.getClass();
boolean embeddable = pc.isAnnotationPresent(jakarta.persistence.Embeddable.class);
if (embeddable && hqlSelectItems.contains(":" + paramName)) throw new IllegalArgumentException("composite param in select");
} Type guard
static boolean isComposite(EntityManager em, Object v) {
return v != null && em.getMetamodel().getEmbeddables().stream()
.anyMatch(et -> et.getJavaType() == v.getClass());
} Try / catch
catch (SemanticException e) { if (e.getMessage().contains("Composite query parameter")) { /* move param to WHERE, select entity components instead */ } else throw e; } Prevention
- Never place bound parameters in the select list; parameters belong in predicates
- Project entity attributes (e.id.part), not parameter echoes
- Add a query lint for ':name' occurring between SELECT and FROM
When it happens
Trigger: HQL 'select :empId from Employee e' where :empId is bound to an EmbeddedId/composite value; criteria multiselect(cb.parameter(EmbeddedId.class)) or selecting a parameter whose type resolves to an embeddable; 'select e.id from ...' variants where e.id is an embedded id get inlined fine, but explicitly binding a composite parameter into the select list triggers it
Common situations: Reports trying to echo a composite filter value back as a result column; mapping a primary key as @EmbeddedId (composite key) and writing generic queries that project bound parameters; migrating from Hibernate 5 where some tuple-in-select cases were tolerated or rendered differently.
Related errors
- Non-aggregate composite paths cannot be TREAT-ed
- Property '" + getPath( propertyHolder, inferredData ) + "' b
- Attribute '%s' of entity '%s' is mapped by association '%s'
- Not implemented yet
- Could not resolve attribute '%s' of '%s'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/06b6a0cf333e39a4.
Report an issue: GitHub.