{"record":{"id":"a62e8f08205d3e68","repo":"hibernate/hibernate-orm","slug":"inconsistent-types-for-cycle-mark-values","errorCode":null,"errorMessage":"Inconsistent types for cycle mark values: [{}, {}]","messagePattern":"Inconsistent types for cycle mark values: \\[(.+?), (.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/cte/SqmCteStatement.java","lineNumber":317,"sourceCode":"\t\t\tString cyclePathAttributeName,\n\t\t\tX cycleValue,\n\t\t\tX noCycleValue,\n\t\t\tList<JpaCteCriteriaAttribute> cycleAttributes) {\n\t\tif ( cycleMarkAttributeName == null || cycleAttributes == null || cycleAttributes.isEmpty() ) {\n\t\t\tthis.cycleMarkAttributeName = null;\n\t\t\tthis.cyclePathAttributeName = null;\n\t\t\tthis.cycleValue = null;\n\t\t\tthis.noCycleValue = null;\n\t\t\tthis.cycleAttributes = Collections.emptyList();\n\t\t}\n\t\telse {\n\t\t\tif ( cycleValue == null || noCycleValue == null ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Null is an illegal value for cycle mark values!\" );\n\t\t\t}\n\t\t\tfinal SqmExpression<X> cycleValueLiteral = nodeBuilder().literal( cycleValue );\n\t\t\tfinal SqmExpression<X> noCycleValueLiteral = nodeBuilder().literal( noCycleValue );\n\t\t\tif ( cycleValueLiteral.getNodeType() != noCycleValueLiteral.getNodeType() ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Inconsistent types for cycle mark values: [\" + cycleValueLiteral.getNodeType() + \", \" + noCycleValueLiteral.getNodeType() + \"]\" );\n\t\t\t}\n\t\t\tfinal List<SqmCteTableColumn> attributes = new ArrayList<>( cycleAttributes.size() );\n\t\t\tfor ( JpaCteCriteriaAttribute cycleAttribute : cycleAttributes ) {\n\t\t\t\tif ( !cteTable.getAttributes().contains( cycleAttribute ) ) {\n\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\"Illegal cycle attribute '\" +\n\t\t\t\t\t\t\t\t\t( cycleAttribute == null ? \"null\" : cycleAttribute.getName() ) +\n\t\t\t\t\t\t\t\t\t\"' passed, which is not part of the JpaCteCriteria!\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tattributes.add( (SqmCteTableColumn) cycleAttribute );\n\t\t\t}\n\t\t\tthis.cycleMarkAttributeName = cycleMarkAttributeName;\n\t\t\tthis.cyclePathAttributeName = cyclePathAttributeName;\n\t\t\tthis.cycleValue = (SqmLiteral<Object>) cycleValueLiteral;\n\t\t\tthis.noCycleValue = (SqmLiteral<Object>) noCycleValueLiteral;\n\t\t\tthis.cycleAttributes = attributes;\n\t\t}","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/cte/SqmCteStatement.java#L299-L335","documentation":"cycle(...) wraps cycleValue and noCycleValue in SqmLiteral expressions and compares getNodeType() of the two literals; if the types differ (for example a String mark vs an Integer mark, or boolean vs int) it throws IllegalArgumentException listing both types. The two cycle mark values must map to the same node type so the rendered SQL has consistent column types.","triggerScenarios":"cte.cycle(\"isCycle\", \"path\", true, 1, columns), or (\"isCycle\", \"path\", \"T\", 0, columns): any pair where the values have different runtime types producing different literal node types.","commonSituations":"Loosely-typed helper code where the two values come from different sources (config vs constant); changing one literal ('Y' vs 1) during refactoring; boxed types that differ between the two parameters.","solutions":["Use a matching pair of the same type: true/false, 1/0 or \"Y\"/\"N\".","Type the helper method as <X> and take both values as X so the compiler enforces identical types."],"exampleFix":"// before\ncte.cycle( \"isCycle\", \"path\", true, 1, columns ); // boolean vs int\n// after\ncte.cycle( \"isCycle\", \"path\", true, false, columns );","handlingStrategy":"validation","validationCode":"static <X> void assertSameType(X cycleValue, X noCycleValue) {\n    if ( !cycleValue.getClass().equals( noCycleValue.getClass() ) ) {\n        throw new IllegalArgumentException( \"Cycle mark values must share one type\" );\n    }\n}\n// then: cte.cycle( \"m\", \"p\", v1, v2, cols );","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass a literal pair of one type: true/false, 1/0 or \"Y\"/\"N\".","Type helper methods as <X> cycle(String, String, X, X, List<...>) so both values share the compile-time type.","Remember the comparison happens on the SQM literal node type after literal() conversion."],"tags":["hibernate","criteria-api","cte","cycle-clause","type-mismatch"],"backgroundTag":"type-mismatch-between-values","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}