hibernate/hibernate-orm · error · IllegalArgumentException

Illegal combination of Tuple resultType and (non-JpaTupleBui

Error message

Illegal combination of Tuple resultType and (non-JpaTupleBuilder) TupleTransformer: {}

What it means

When a query runs with Tuple as its result type, Hibernate must build TupleMetadata (tuple elements plus aliases) from the Sqm selections. That is only possible when no custom row transformer is involved, so QueryHelper.getTupleMetadata throws IllegalArgumentException for any TupleTransformer that is not a JpaTupleBuilder. In practice the combination is contradictory: the transformer would replace the tuples whose metadata Hibernate is trying to compute.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/internal/QueryHelper.java:153

		final var selection = selections.size() == 1 ? selections.get( 0 ) : null;
		return isHqlTuple( selection )
			|| !isInstantiableWithoutMetadata( resultType )
				&& !isSelectionAssignableToResultType( selection, resultType );
	}

	private static boolean isInstantiableWithoutMetadata(Class<?> resultType) {
		return resultType == null
			|| resultType.isArray()
			|| Object.class == resultType
			|| List.class == resultType;
	}

	private static TupleMetadata getTupleMetadata(List<SqmSelection<?>> selections, TupleTransformer<?> rowTransformer) {
		if ( rowTransformer == null ) {
			return new TupleMetadata( buildTupleElementArray( selections ), buildTupleAliasArray( selections ) );
		}
		else {
			throw new IllegalArgumentException(
					"Illegal combination of Tuple resultType and (non-JpaTupleBuilder) TupleTransformer: "
							+ rowTransformer
			);
		}
	}

	private static TupleElement<?>[] buildTupleElementArray(List<SqmSelection<?>> selections) {
		final int selectionsSize = selections.size();
		if ( selectionsSize == 1 ) {
			final var selectableNode = selections.get( 0 ).getSelectableNode();
			if ( selectableNode instanceof CompoundSelection<?> ) {
				final var selectionItems = selectableNode.getSelectionItems();
				final int itemsSize = selectionItems.size();
				final var elements = new TupleElement<?>[itemsSize];
				for ( int i = 0; i < itemsSize; i++ ) {
					elements[i] = selectionItems.get( i );
				}
				return elements;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Drop Tuple and map straight to a DTO: use a constructor projection 'select new com.acme.Dto(...)' and leave the transformer off.
  2. Or remove the transformer and read the Tuple directly: tuple.get("alias", Type.class).
  3. If transformation is required, apply it to the List<Tuple> after getResultList() in plain Java.

Example fix

// before
var q = session.createQuery("select p.name, p.age from Person p", Tuple.class);
q.setTupleTransformer(tuple -> transform(tuple)); // throws

// after - DTO projection, no Tuple, no transformer
var q = session.createQuery(
    "select new com.acme.PersonRow(p.name, p.age) from Person p",
    PersonRow.class);
// or read the Tuple directly: tuple.get("name", String.class)
Defensive patterns

Strategy: validation

Validate before calling

static void setTransformerSafe(org.hibernate.query.SelectionQuery<?> q,
        org.hibernate.query.TupleTransformer<?> transformer) {
    if (transformer != null && q.getResultType() == Tuple.class)
        throw new IllegalArgumentException(
            "Tuple result type cannot be combined with a TupleTransformer; use a DTO projection");
}

Prevention

When it happens

Trigger: em.createQuery(hql, Tuple.class) or session.createQuery(..., Tuple.class) followed by setTupleTransformer(customTransformer) (or a legacy setResultTransformer) on the same query. The error surfaces when the result is prepared for execution.

Common situations: Hibernate 5 to 6 migration where setResultTransformer was used together with Tuple; teams wanting alias-based metadata and post-processing at once; transformers kept around after switching the result type to Tuple.

Related errors


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