{"record":{"id":"c300c0885c4d3aa8","repo":"hibernate/hibernate-orm","slug":"illegal-combination-of-tuple-resulttype-and-non-j","errorCode":null,"errorMessage":"Illegal combination of Tuple resultType and (non-JpaTupleBuilder) TupleTransformer: {}","messagePattern":"Illegal combination of Tuple resultType and \\(non-JpaTupleBuilder\\) TupleTransformer: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/internal/QueryHelper.java","lineNumber":153,"sourceCode":"\t\tfinal var selection = selections.size() == 1 ? selections.get( 0 ) : null;\n\t\treturn isHqlTuple( selection )\n\t\t\t|| !isInstantiableWithoutMetadata( resultType )\n\t\t\t\t&& !isSelectionAssignableToResultType( selection, resultType );\n\t}\n\n\tprivate static boolean isInstantiableWithoutMetadata(Class<?> resultType) {\n\t\treturn resultType == null\n\t\t\t|| resultType.isArray()\n\t\t\t|| Object.class == resultType\n\t\t\t|| List.class == resultType;\n\t}\n\n\tprivate static TupleMetadata getTupleMetadata(List<SqmSelection<?>> selections, TupleTransformer<?> rowTransformer) {\n\t\tif ( rowTransformer == null ) {\n\t\t\treturn new TupleMetadata( buildTupleElementArray( selections ), buildTupleAliasArray( selections ) );\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Illegal combination of Tuple resultType and (non-JpaTupleBuilder) TupleTransformer: \"\n\t\t\t\t\t\t\t+ rowTransformer\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate static TupleElement<?>[] buildTupleElementArray(List<SqmSelection<?>> selections) {\n\t\tfinal int selectionsSize = selections.size();\n\t\tif ( selectionsSize == 1 ) {\n\t\t\tfinal var selectableNode = selections.get( 0 ).getSelectableNode();\n\t\t\tif ( selectableNode instanceof CompoundSelection<?> ) {\n\t\t\t\tfinal var selectionItems = selectableNode.getSelectionItems();\n\t\t\t\tfinal int itemsSize = selectionItems.size();\n\t\t\t\tfinal var elements = new TupleElement<?>[itemsSize];\n\t\t\t\tfor ( int i = 0; i < itemsSize; i++ ) {\n\t\t\t\t\telements[i] = selectionItems.get( i );\n\t\t\t\t}\n\t\t\t\treturn elements;","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/internal/QueryHelper.java#L135-L171","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Drop Tuple and map straight to a DTO: use a constructor projection 'select new com.acme.Dto(...)' and leave the transformer off.","Or remove the transformer and read the Tuple directly: tuple.get(\"alias\", Type.class).","If transformation is required, apply it to the List<Tuple> after getResultList() in plain Java."],"exampleFix":"// before\nvar q = session.createQuery(\"select p.name, p.age from Person p\", Tuple.class);\nq.setTupleTransformer(tuple -> transform(tuple)); // throws\n\n// after - DTO projection, no Tuple, no transformer\nvar q = session.createQuery(\n    \"select new com.acme.PersonRow(p.name, p.age) from Person p\",\n    PersonRow.class);\n// or read the Tuple directly: tuple.get(\"name\", String.class)","handlingStrategy":"validation","validationCode":"static void setTransformerSafe(org.hibernate.query.SelectionQuery<?> q,\n        org.hibernate.query.TupleTransformer<?> transformer) {\n    if (transformer != null && q.getResultType() == Tuple.class)\n        throw new IllegalArgumentException(\n            \"Tuple result type cannot be combined with a TupleTransformer; use a DTO projection\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Choose one strategy: Tuple for alias-based access, or DTO projection with a transformer.","During Hibernate 5 to 6 migration, replace setResultTransformer+Tuple with DTO projections.","Keep result-type decisions in one factory method per query."],"tags":["hibernate","tuple","tupletransformer","result-type","migration"],"backgroundTag":"result-transformer-conflict","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}