{"record":{"id":"9790c92a56f61532","repo":"hibernate/hibernate-orm","slug":"unsupported-tuple-comparison-combination-lhs-is-n","errorCode":null,"errorMessage":"Unsupported tuple comparison combination. LHS is neither a tuple nor a tuple subquery but RHS is a tuple: ","messagePattern":"Unsupported tuple comparison combination\\. LHS is neither a tuple nor a tuple subquery but RHS is a tuple: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java","lineNumber":8630,"sourceCode":"\t\t\t\t\t\t\tlhsExpression,\n\t\t\t\t\t\t\tcomparisonPredicate.getOperator(),\n\t\t\t\t\t\t\tcomparisonPredicate.getRightHandExpression()\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\temulateSubQueryRelationalRestrictionPredicate(\n\t\t\t\t\t\t\tcomparisonPredicate,\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\t(SelectStatement) lhsExpression,\n\t\t\t\t\t\t\trhsTuple,\n\t\t\t\t\t\t\tthis::renderSelectTupleComparison,\n\t\t\t\t\t\t\t// Since we switch the order of operands, we have to invert the operator\n\t\t\t\t\t\t\tcomparisonPredicate.getOperator().invert()\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Unsupported tuple comparison combination. LHS is neither a tuple nor a tuple subquery but RHS is a tuple: \" + comparisonPredicate );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\trenderComparison(\n\t\t\t\t\tcomparisonPredicate.getLeftHandExpression(),\n\t\t\t\t\tcomparisonPredicate.getOperator(),\n\t\t\t\t\tcomparisonPredicate.getRightHandExpression()\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate boolean needsTupleComparisonEmulation(ComparisonOperator operator) {\n\t\tif ( !dialect.supportsRowValueConstructorSyntax() ) {\n\t\t\treturn true;\n\t\t}\n\t\treturn switch (operator) {\n\t\t\tcase LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL ->","sourceCodeStart":8612,"sourceCodeEnd":8648,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java#L8612-L8648","documentation":"While flattening a ComparisonPredicate whose right-hand side is a SqlTuple, the translator accepts only a tuple or tuple subquery on the left-hand side. If the RHS is a tuple but the LHS is neither, the AST combination is considered impossible/unsupported and this IllegalStateException (dumping the predicate) is thrown - typically indicating a malformed or unusual query model rather than a supported feature gap.","triggerScenarios":"A query model where a SqlTuple ends up on one side of a comparison while the other side is a plain scalar expression - usually produced by dialect-specific comparison flattening, criteria misuse, or SQM rewriting - rather than by plain HQL.","commonSituations":"Hibernate internal invariant hit via complex id-class/embeddable comparisons on specific dialects; custom SqmTranslator/SQM function descriptors emitting tuples into comparisons; rare HHH bugs fixed across 6.x versions.","solutions":["Rewrite the comparison to compare matching shapes (tuple vs tuple, scalar vs scalar)","Compare component-wise: a = :a and b = :b instead of tuple syntax","Upgrade to the latest Hibernate 6.x - report the query to HHH if it reproduces, since this signals an internal inconsistency"],"exampleFix":"// before\n... where (e.embeddedA, e.embeddedB) = :scalarParam // tuple vs non-tuple\n\n// after\n... where e.embeddedA = :a and e.embeddedB = :b","handlingStrategy":"try-catch","validationCode":"// When building comparisons programmatically, keep both sides shape-compatible\nboolean lhsTuple = lhs instanceof SqlTuple || lhs instanceof SelectStatement;\nboolean rhsTuple = rhs instanceof SqlTuple;\nif (rhsTuple && !lhsTuple) { /* force lhs to a tuple or rhs to scalar before adding the predicate */ }","typeGuard":null,"tryCatchPattern":"try {\n    query.list();\n} catch (IllegalStateException e) {\n    if (String.valueOf(e.getMessage()).startsWith(\"Unsupported tuple comparison combination\")) {\n        // log the predicate, rewrite as component-wise comparisons; report to HHH with the query\n    } else throw e;\n}","preventionTips":["Compare tuples with tuples and scalars with scalars; never mix shapes","Keep Hibernate updated - this invariant failure often marks a fixed bug","Include the full query when reporting occurrences upstream"],"tags":["hibernate","tuple-comparison","query-model","internal-invariant","sql-translator"],"backgroundTag":"tuple-comparison-emulation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}