hibernate/hibernate-orm · error · IllegalArgumentException

Selection item in a multi-select cannot contain compound tup

Error message

Selection item in a multi-select cannot contain compound tuple-valued elements

What it means

Twin rule of the array variant: multiselect items must not be compound selections whose Java type is Tuple (produced by cb.tuple(...)). The JPA contract forbids tuple- or array-valued compound items as arguments to multiselect because the final row composition is governed by the multiselect call itself, so Hibernate's checkMultiselect rejects them immediately.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java:1339

	 * @param selections The selection varargs to check
	 *
	 * @throws IllegalArgumentException If the selection items are not valid per
	 *         according to {@linkplain CriteriaQuery#multiselect this documentation}.
	 *         <i>&quot;An argument to the multiselect method must not be a tuple-
	 *         or array-valued compound selection item.&quot;</i>
	 */
	private void checkMultiselect(List<? extends Selection<?>> selections) {
		final HashSet<String> aliases = new HashSet<>( determineProperSizing( selections.size() ) );
		for ( var selection : selections ) {
			if ( selection.isCompoundSelection() ) {
				final Class<?> javaType = selection.getJavaType();
				if ( javaType.isArray() ) {
					throw new IllegalArgumentException(
							"Selection item in a multi-select cannot contain compound array-valued elements"
					);
				}
				if ( Tuple.class.isAssignableFrom( javaType ) ) {
					throw new IllegalArgumentException(
							"Selection item in a multi-select cannot contain compound tuple-valued elements"
					);
				}
			}
			final String alias = selection.getAlias();
			if ( StringHelper.isNotEmpty( alias ) && !aliases.add( alias ) ) {
				throw new IllegalArgumentException( "Multi-select expressions have duplicate alias '" + alias + "'" );
			}
		}
	}

	@Nonnull
	@Override
	public <N extends Number> SqmExpression<Double> avg(@Nonnull Expression<N> argument) {
		return getFunctionDescriptor( "avg" ).generateSqmExpression(
				(SqmTypedNode<?>) argument,
				null,
				queryEngine

View on GitHub (pinned to fad1729dce)

Solutions

  1. Spread the tuple's arguments into multiselect: multiselect(root.get("a"), root.get("b"), root.get("c")).
  2. Or keep tuple() as the sole top-level selection: query.select(cb.tuple(a, b, c)).
  3. Audit helper methods that return Selection<Tuple>/Selection<Object[]> and stop feeding them to multiselect.

Example fix

// before
query.multiselect(cb.tuple(root.get("sku"), root.get("name")), root.get("qty"));
// -> Selection item in a multi-select cannot contain compound tuple-valued elements

// after
query.multiselect(root.get("sku"), root.get("name"), root.get("qty"));
Defensive patterns

Strategy: validation

Validate before calling

boolean hasNestedTupleItem(List<? extends Selection<?>> items) {
    for (Selection<?> s : items) {
        if (s.isCompoundSelection() && Tuple.class.isAssignableFrom(s.getJavaType())) return true;
    }
    return false;
}
if (hasNestedTupleItem(selections)) throw new IllegalArgumentException("flatten tuple() items before multiselect");

Type guard

static boolean isCompoundTupleItem(Selection<?> s) {
    return s.isCompoundSelection() && Tuple.class.isAssignableFrom(s.getJavaType());
}

Try / catch

try {
    query.multiselect(items);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("tuple-valued")) { /* spread cb.tuple(...) args into multiselect */ }
    else throw e;
}

Prevention

When it happens

Trigger: query.multiselect(cb.tuple(root.get("a"), root.get("b")), root.get("c")); reusing a helper that returns Selection<Tuple> as one argument of multiselect; migrating a Tuple query into multiselect without unwrapping the tuple(...) wrapper.

Common situations: Dynamic report projections assembled from per-column helper methods where one helper already groups columns into a tuple; refactors from query.select(cb.tuple(...)) to multiselect(...).

Related errors


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