{"record":{"id":"e4fd08de547a80b3","repo":"hibernate/hibernate-orm","slug":"illegal-cycle-attribute-passed-which-is-not","errorCode":null,"errorMessage":"Illegal cycle attribute '{}' passed, which is not part of the JpaCteCriteria!","messagePattern":"Illegal cycle attribute '(.+?)' passed, which is not part of the JpaCteCriteria!","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/cte/SqmCteStatement.java","lineNumber":322,"sourceCode":"\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}\n\t}\n\n\t@Override\n\tpublic <X> X accept(SemanticQueryWalker<X> walker) {\n\t\treturn walker.visitCteStatement( this );","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/cte/SqmCteStatement.java#L304-L340","documentation":"The cycle(...) overload also validates every entry of cycleAttributes against cteTable.getAttributes(); only attributes that are columns of the CTE type itself may be used for cycle detection. Passing an entity attribute from the base query (or an attribute of another CTE) throws IllegalArgumentException naming the offending attribute.","triggerScenarios":"cte.cycle(\"isCycle\", \"path\", true, false, List.of(baseRootAttr)) where baseRootAttr is a SingularAttribute/Path of the underlying entity instead of a JpaCteCriteriaAttribute of the CTE type.","commonSituations":"Converting HQL 'CYCLE id SET ...' to criteria and reusing the entity metamodel attribute instead of the CTE attribute; building cycle clauses in generic helpers that receive entity attributes.","solutions":["Pass only attributes of the CTE type obtained from the JpaCteCriteria created by with(...).","Resolve columns by name via the CTE type's getAttribute(name).","If a needed column is missing from the CTE, select it in the CTE's base query first so it becomes a CTE attribute."],"exampleFix":"// before\ncte.cycle( \"isCycle\", \"path\", true, false, List.of( personRoot.getModelfield() ) ); // entity attribute\n// after\nList<JpaCteCriteriaAttribute> cols = List.of( /* attributes of the CTE type from with(...) */ );\ncte.cycle( \"isCycle\", \"path\", true, false, cols );","handlingStrategy":"validation","validationCode":"List<JpaCteCriteriaAttribute> ok = cycleColumns.stream()\n    .filter( a -> cteType.getAttributes().contains( a ) )\n    .toList();\nif ( ok.size() != cycleColumns.size() ) {\n    throw new IllegalArgumentException( \"Some cycle columns are not CTE attributes\" );\n}\ncte.cycle( \"isCycle\", \"path\", true, false, ok );","typeGuard":"static boolean isCteAttribute(JpaCteCriteriaType<?> type, JpaCteCriteriaAttribute a) {\n    return type.getAttributes().contains( a );\n}","tryCatchPattern":null,"preventionTips":["Source cycle columns from the CTE type returned by with(...), never from entity metamodel attributes.","Select the recursion column (e.g. parent id) into the CTE base query so it exists as a CTE attribute.","Wrap CTE attribute plumbing in one helper per statement so search() and cycle() share the same attribute list."],"tags":["hibernate","criteria-api","cte","cycle-clause","recursive-query"],"backgroundTag":"unknown-attribute-reference","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}