hibernate/hibernate-orm · error · IllegalArgumentException
Inconsistent types for cycle mark values
Error message
Inconsistent types for cycle mark values: [{}, {}] What it means
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.
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.
Example fix
// before cte.cycle( "isCycle", "path", true, 1, columns ); // boolean vs int // after cte.cycle( "isCycle", "path", true, false, columns );
Defensive patterns
Strategy: validation
Validate before calling
static <X> void assertSameType(X cycleValue, X noCycleValue) {
if ( !cycleValue.getClass().equals( noCycleValue.getClass() ) ) {
throw new IllegalArgumentException( "Cycle mark values must share one type" );
}
}
// then: cte.cycle( "m", "p", v1, v2, cols ); Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Illegal cycle attribute
- Null is an illegal value for cycle mark values!
- A CTE with the label
- Cannot compare left expression of type
- Cannot correlate from node
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/a62e8f08205d3e68.
Report an issue: GitHub.
Appendix: source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/cte/SqmCteStatement.java:317
String cyclePathAttributeName,
X cycleValue,
X noCycleValue,
List<JpaCteCriteriaAttribute> cycleAttributes) {
if ( cycleMarkAttributeName == null || cycleAttributes == null || cycleAttributes.isEmpty() ) {
this.cycleMarkAttributeName = null;
this.cyclePathAttributeName = null;
this.cycleValue = null;
this.noCycleValue = null;
this.cycleAttributes = Collections.emptyList();
}
else {
if ( cycleValue == null || noCycleValue == null ) {
throw new IllegalArgumentException( "Null is an illegal value for cycle mark values!" );
}
final SqmExpression<X> cycleValueLiteral = nodeBuilder().literal( cycleValue );
final SqmExpression<X> noCycleValueLiteral = nodeBuilder().literal( noCycleValue );
if ( cycleValueLiteral.getNodeType() != noCycleValueLiteral.getNodeType() ) {
throw new IllegalArgumentException( "Inconsistent types for cycle mark values: [" + cycleValueLiteral.getNodeType() + ", " + noCycleValueLiteral.getNodeType() + "]" );
}
final List<SqmCteTableColumn> attributes = new ArrayList<>( cycleAttributes.size() );
for ( JpaCteCriteriaAttribute cycleAttribute : cycleAttributes ) {
if ( !cteTable.getAttributes().contains( cycleAttribute ) ) {
throw new IllegalArgumentException(
"Illegal cycle attribute '" +
( cycleAttribute == null ? "null" : cycleAttribute.getName() ) +
"' passed, which is not part of the JpaCteCriteria!"
);
}
attributes.add( (SqmCteTableColumn) cycleAttribute );
}
this.cycleMarkAttributeName = cycleMarkAttributeName;
this.cyclePathAttributeName = cyclePathAttributeName;
this.cycleValue = (SqmLiteral<Object>) cycleValueLiteral;
this.noCycleValue = (SqmLiteral<Object>) noCycleValueLiteral;
this.cycleAttributes = attributes;
}View on GitHub (pinned to fad1729dce)