{"record":{"id":"b634ba40f0628bb8","repo":"hibernate/hibernate-orm","slug":"tuple-size-mismatch","errorCode":null,"errorMessage":"Tuple size mismatch","messagePattern":"Tuple size mismatch","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InterSystemsIRISSqlAstTranslator.java","lineNumber":81,"sourceCode":"\t\tif ( operator == ComparisonOperator.EQUAL || operator == ComparisonOperator.NOT_EQUAL ) {\n\t\t\temulateTupleComparisonSelections( lhsSelections, rhsTuple, operator );\n\t\t}\n\t\telse {\n\n\t\t\tsuper.renderTupleComparisonStandard( lhsSelections, rhsTuple, operator );\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected void emulateTupleComparisonSelections(\n\t\t\tList<SqlSelection> lhsSelections,\n\t\t\tSqlTuple rhsTuple,\n\t\t\tComparisonOperator operator\n\t) {\n\t\tfinal List<Expression> rhsExpressions = (List<Expression>) rhsTuple.getExpressions();\n\n\t\tif ( lhsSelections.size() != rhsExpressions.size() ) {\n\t\t\tthrow new IllegalArgumentException( \"Tuple size mismatch\" );\n\t\t}\n\n\t\tfinal String joiner = ( operator == ComparisonOperator.EQUAL ) ? \" and \" : \" or \";\n\n\t\tappendSql( OPEN_PARENTHESIS );\n\t\tfor ( int i = 0; i < lhsSelections.size(); i++ ) {\n\t\t\tif ( i > 0 ) {\n\t\t\t\tappendSql( joiner );\n\t\t\t}\n\n\t\t\tlhsSelections.get( i ).getExpression().accept( this );\n\t\t\tappendSql( operator.sqlText() );\n\t\t\trhsExpressions.get( i ).accept( this );\n\t\t}\n\t\tappendSql( CLOSE_PARENTHESIS );\n\t}\n\n\t@Override","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InterSystemsIRISSqlAstTranslator.java#L63-L99","documentation":"Because IRIS lacks row-value constructor syntax, InterSystemsIRISSqlAstTranslator.emulateTupleComparisonSelections() expands a tuple comparison such as (a, b) = (x, y) into component-wise AND/OR expressions. It first asserts the left-hand select items and right-hand tuple have the same arity; a mismatch throws IllegalArgumentException('Tuple size mismatch') during SQL generation.","triggerScenarios":"An HQL tuple/row-value comparison whose sides have different arity on the IRIS dialect, e.g. '(e.a, e.b, e.c) = (1, 2)' or comparing a composite-id tuple against a list of the wrong length — a condition that should normally be rejected earlier by SQM validation but slips through to the IRIS-specific emulation.","commonSituations":"Hand-written tuple predicates with mismatched literals; dynamic query builders that zip columns and values from different sources; Hibernate version mismatches where an arity bug in SQM validation lets the query reach the translator.","solutions":["Fix the query so both tuple sides have the same number of elements","Replace the tuple comparison with explicit scalar comparisons combined by AND/OR","If your query looks valid, upgrade Hibernate — a tuple reaching this code with mismatched arity is worth reporting as a bug with a reproducer"],"exampleFix":"// before - arity mismatch (3 vs 2)\n\"select o from Order o where (o.a, o.b, o.c) = (1, 2)\"\n\n// after - match arity, or compare scalars explicitly\n\"select o from Order o where (o.a, o.b, o.c) = (1, 2, 3)\"\n// or\n\"select o from Order o where o.a = 1 and o.b = 2 and o.c = 3\"","handlingStrategy":"try-catch","validationCode":"// before executing, check tuple arity in the predicate you build\nint columns = 2; // e.g. composite id parts\nif ( values.size() != columns ) {\n    throw new IllegalArgumentException(\n        \"tuple comparison arity mismatch: \" + columns + \" vs \" + values.size());\n}\nPredicate p = cb.equal(cb.tuple(root.get(\"a\"), root.get(\"b\")), cb.tuple(...));","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql).getResultList();\n} catch (IllegalArgumentException e) {\n    if ( \"Tuple size mismatch\".equals(e.getMessage()) ) {\n        // fix the literal list length to match the tuple and rebuild the query\n    }\n    throw e;\n}","preventionTips":["Build tuple comparisons programmatically so both sides are zipped from one source list","Prefer explicit AND-ed scalar comparisons over row-value syntax on dialects without row constructors","Add unit tests for dynamic predicate builders that assemble tuple literals"],"tags":["hibernate","intersystems-iris","tuple-comparison","row-value","query-validation"],"backgroundTag":"tuple-comparison-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}