hibernate/hibernate-orm · error · UnsupportedOperationException

Domain result for non-scalar subquery shouldn't be created

Error message

Domain result for non-scalar subquery shouldn't be created

What it means

SelectStatement.createDomainResult builds a DomainResult when a subquery SelectStatement is used as a scalar expression. It only supports subqueries whose first QuerySpec has exactly one SqlSelection; anything else - multiple select items, or a single entity/composite selection that expands to several SQL selections - throws UnsupportedOperationException('Domain result for non-scalar subquery shouldn't be created').

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/SelectStatement.java:96

			final SqlSelection first = sqlSelections.get( 0 );
			final JdbcMapping jdbcMapping = first.getExpressionType().getSingleJdbcMapping();
			final SqlSelection sqlSelection =
					creationState.getSqlAstCreationState().getSqlExpressionResolver()
							.resolveSqlSelection(
									this,
									jdbcMapping.getJdbcJavaType(),
									null,
									creationState.getSqlAstCreationState().getCreationContext()
											.getTypeConfiguration()
							);
			return new BasicResult<>(
					sqlSelection.getValuesArrayPosition(),
					resultVariable,
					jdbcMapping
			);
		}
		else {
			throw new UnsupportedOperationException("Domain result for non-scalar subquery shouldn't be created");
		}
	}

	@Override
	public void applySqlSelections(DomainResultCreationState creationState) {
		final TypeConfiguration typeConfiguration =
				creationState.getSqlAstCreationState().getCreationContext()
						.getTypeConfiguration();
		final SqlExpressionResolver expressionResolver =
				creationState.getSqlAstCreationState().getSqlExpressionResolver();
		for ( SqlSelection sqlSelection :
				queryPart.getFirstQuerySpec().getSelectClause().getSqlSelections() ) {
			sqlSelection.getExpressionType().forEachJdbcType(
					(index, jdbcMapping) -> {
						expressionResolver
								.resolveSqlSelection(
										this,
										jdbcMapping.getJdbcJavaType(),

View on GitHub (pinned to fad1729dce)

Solutions

  1. Reduce the subquery to exactly one select item (one column or basic expression)
  2. Select a single attribute (e.g. the id) instead of the whole entity in the subquery
  3. Rewrite tuple comparisons as an exists() subquery or AND-ed scalar comparisons
  4. In Criteria, use a single-valued Subquery<Long>/Expression rather than multiselect

Example fix

// before (HQL)
where e.age > ( select e1.age, e1.id from Employee e1 where e1.dept = e.dept )

// after
where e.age > ( select max(e1.age) from Employee e1 where e1.dept = e.dept )
Defensive patterns

Strategy: validation

Validate before calling

// JPQL/HQL: keep subqueries in scalar positions single-item
String hql = "where e.age > ( select max(e1.age) from Employee e1 where e1.dept = e.dept )";

Try / catch

try {
    return session.createQuery( hql, Integer.class ).getSingleResult();
} catch ( UnsupportedOperationException e ) {
    if ( e.getMessage() != null && e.getMessage().contains( "non-scalar subquery" ) ) {
        throw new IllegalArgumentException( "Subquery must select exactly one value: " + hql, e );
    }
    throw e;
}

Prevention

When it happens

Trigger: HQL/Criteria where a subquery occupies a scalar position (comparison, select item, function argument) but selects more than one thing: 'where e.age > (select e1.age, e1.id from Employee e1)', 'select (select e1 from Employee e1) from ...', or a subquery selecting an entity/embeddable. SQM translators building domain results for expression-position subqueries.

Common situations: Porting SQL tuple comparisons '(a,b) = (select x,y ...)' to HQL; subqueries selecting a whole entity instead of one column; Criteria Subquery multiselect used inside a where expression; stricter enforcement surfacing after migrating to Hibernate 6.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/21b8c3a6ae49f964. Report an issue: GitHub.