hibernate/hibernate-orm · error · IllegalArgumentException

Illegal search order attribute '{}' passed, which is not par

Error message

Illegal search order attribute '{}' passed, which is not part of the JpaCteCriteria!

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/cte/SqmCteStatement.java:281

	@Nonnull
	@Override
	public JpaCteCriteriaType<T> getType() {
		return cteTable;
	}

	@Override
	public void search(CteSearchClauseKind kind, String searchAttributeName, List<JpaSearchOrder> searchOrders) {
		if ( kind == null || searchAttributeName == null || searchOrders == null || searchOrders.isEmpty() ) {
			this.searchClauseKind = null;
			this.searchBySpecifications = Collections.emptyList();
			this.searchAttributeName = null;
		}
		else {
			final List<JpaSearchOrder> orders = new ArrayList<>( searchOrders.size() );
			for ( JpaSearchOrder order : searchOrders ) {
				if ( !cteTable.getAttributes().contains( order.getAttribute() ) ) {
					throw new IllegalArgumentException(
							"Illegal search order attribute '" +
									( order.getAttribute() == null ? "null" : order.getAttribute().getName() ) +
									"' passed, which is not part of the JpaCteCriteria!"
					);
				}
				orders.add( order );
			}
			this.searchClauseKind = kind;
			this.searchAttributeName = searchAttributeName;
			//noinspection unchecked
			this.searchBySpecifications = (List<SqmSearchClauseSpecification>) (List<?>) orders;
		}
	}

	@Override
	public <X> void cycleUsing(
			String cycleMarkAttributeName,
			String cyclePathAttributeName,

View on GitHub (pinned to fad1729dce)

Solutions

  1. 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).
  2. Look the attribute up by name via the CTE type's getAttribute(name) instead of holding entity paths.
  3. Keep a reference to the attributes returned when the CTE was created and pass those into search().

Example fix

// before
cte.search( DEPTH_FIRST, "seq", List.of( cb.search( baseRoot.get( "id" ) ) ) ); // not a CTE attribute
// after
JpaCteCriteriaAttribute idCol = /* attribute of the CTE type from with(...) */;
cte.search( DEPTH_FIRST, "seq", List.of( cb.search( idCol, SortDirection.ASCENDING ) ) );
Defensive patterns

Strategy: validation

Validate before calling

// only pass orders whose attribute is one of the CTE type's own attributes
List<JpaSearchOrder> safeOrders = new ArrayList<>();
for ( JpaSearchOrder order : wantedOrders ) {
    if ( cteType.getAttributes().contains( order.getAttribute() ) ) {
        safeOrders.add( order );
    }
}
cte.search( kind, "search", safeOrders );

Type guard

static boolean isCteAttribute(JpaCteCriteria<?> cte, JpaSearchOrder order) {
    return order.getAttribute() instanceof JpaCteCriteriaAttribute
        && cte.getCteTable().getAttributes().contains( order.getAttribute() );
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/a8010a71ed98124c. Report an issue: GitHub.