{"record":{"id":"a8010a71ed98124c","repo":"hibernate/hibernate-orm","slug":"illegal-search-order-attribute-passed-which","errorCode":null,"errorMessage":"Illegal search order attribute '{}' passed, which is not part of the JpaCteCriteria!","messagePattern":"Illegal search order 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":281,"sourceCode":"\n\t@Nonnull\n\t@Override\n\tpublic JpaCteCriteriaType<T> getType() {\n\t\treturn cteTable;\n\t}\n\n\t@Override\n\tpublic void search(CteSearchClauseKind kind, String searchAttributeName, List<JpaSearchOrder> searchOrders) {\n\t\tif ( kind == null || searchAttributeName == null || searchOrders == null || searchOrders.isEmpty() ) {\n\t\t\tthis.searchClauseKind = null;\n\t\t\tthis.searchBySpecifications = Collections.emptyList();\n\t\t\tthis.searchAttributeName = null;\n\t\t}\n\t\telse {\n\t\t\tfinal List<JpaSearchOrder> orders = new ArrayList<>( searchOrders.size() );\n\t\t\tfor ( JpaSearchOrder order : searchOrders ) {\n\t\t\t\tif ( !cteTable.getAttributes().contains( order.getAttribute() ) ) {\n\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\"Illegal search order attribute '\" +\n\t\t\t\t\t\t\t\t\t( order.getAttribute() == null ? \"null\" : order.getAttribute().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\torders.add( order );\n\t\t\t}\n\t\t\tthis.searchClauseKind = kind;\n\t\t\tthis.searchAttributeName = searchAttributeName;\n\t\t\t//noinspection unchecked\n\t\t\tthis.searchBySpecifications = (List<SqmSearchClauseSpecification>) (List<?>) orders;\n\t\t}\n\t}\n\n\t@Override\n\tpublic <X> void cycleUsing(\n\t\t\tString cycleMarkAttributeName,\n\t\t\tString cyclePathAttributeName,","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/cte/SqmCteStatement.java#L263-L299","documentation":"SqmCteStatement.search(kind, searchAttributeName, searchOrders) validates every JpaSearchOrder's attribute against cteTable.getAttributes(): only attributes that are columns of the CTE type itself are accepted. Passing an attribute of the underlying entity (e.g. a Path from the base query's root) or of a different CTE throws IllegalArgumentException naming the offending attribute.","triggerScenarios":"cte.search(CteSearchClauseKind.DEPTH_FIRST, \"seq\", List.of(cb.search(root.get(\"id\")))) where the JpaSearchOrder was built from the entity root instead of an attribute of the CTE type returned by with(...). Also passing an attribute of another CTE.","commonSituations":"Building recursive CTEs with a SEARCH clause for ordering; natural mistake of re-using base-query attributes because the CTE attributes must be fetched from the JpaCteCriteriaType (getAttributes()/getAttribute(name)) rather than the entity metamodel.","solutions":["Build search orders only from the CTE type's own attributes: JpaCteCriteriaAttribute from the JpaCteCriteria returned by with(...), e.g. cb.search(cteAttribute, SortDirection.ASCENDING, Nulls.FIRST).","Look the attribute up by name via the CTE type's getAttribute(name) instead of holding entity paths.","Keep a reference to the attributes returned when the CTE was created and pass those into search()."],"exampleFix":"// before\ncte.search( DEPTH_FIRST, \"seq\", List.of( cb.search( baseRoot.get( \"id\" ) ) ) ); // not a CTE attribute\n// after\nJpaCteCriteriaAttribute idCol = /* attribute of the CTE type from with(...) */;\ncte.search( DEPTH_FIRST, \"seq\", List.of( cb.search( idCol, SortDirection.ASCENDING ) ) );","handlingStrategy":"validation","validationCode":"// only pass orders whose attribute is one of the CTE type's own attributes\nList<JpaSearchOrder> safeOrders = new ArrayList<>();\nfor ( JpaSearchOrder order : wantedOrders ) {\n    if ( cteType.getAttributes().contains( order.getAttribute() ) ) {\n        safeOrders.add( order );\n    }\n}\ncte.search( kind, \"search\", safeOrders );","typeGuard":"static boolean isCteAttribute(JpaCteCriteria<?> cte, JpaSearchOrder order) {\n    return order.getAttribute() instanceof JpaCteCriteriaAttribute\n        && cte.getCteTable().getAttributes().contains( order.getAttribute() );\n}","tryCatchPattern":null,"preventionTips":["Build JpaSearchOrder only through HibernateCriteriaBuilder.search(cteAttribute, ...).","Keep the JpaCteCriteria returned by with(...) and take search/cycle attributes from its type, never from the entity root.","If a base-query column is needed for ordering, make sure it is selected as a CTE column first."],"tags":["hibernate","criteria-api","cte","search-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"}