hibernate/hibernate-orm · error · UnsupportedOperationException

CTE joins can not be treated

Error message

CTE joins can not be treated

What it means

SqmCteJoin is Hibernate's SQM (semantic query model) node for joining a CTE declared with `with c as (...)`, built by HQL `join c on ...` or criteria `JpaFrom.join(JpaCteCriteria)`. TREAT downcasts a join to an entity subtype, which requires a polymorphic persistent entity type behind the join; a CTE is an anonymous query-result shape with no metamodel inheritance (SqmCteJoin.getAttribute() returns null). Therefore every treatAs overload on SqmCteJoin fails fast with UnsupportedOperationException the moment it is invoked during query construction, before any SQL is generated.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/from/SqmCteJoin.java:142

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// JPA

	@Override
	@Nonnull
	public SqmCorrelatedCteJoin<T> createCorrelation() {
		return new SqmCorrelatedCteJoin<>( this );
	}

	@Nullable
	@Override
	public PersistentAttribute<? super T, ?> getAttribute() {
		return null;
	}

	@Override
	@Nonnull
	public <S extends T> SqmTreatedJoin<T, T, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias) {
		throw new UnsupportedOperationException( "CTE joins can not be treated" );
	}

	@Override
	@Nonnull
	public <S extends T> SqmTreatedJoin<T, T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias) {
		throw new UnsupportedOperationException( "CTE joins can not be treated" );
	}

	@Override
	@Nonnull
	public <S extends T> SqmTreatedJoin<T, T, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias, boolean fetched) {
		throw new UnsupportedOperationException( "CTE joins can not be treated" );
	}

	@Override
	@Nonnull
	public <S extends T> SqmTreatedJoin<T, T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias, boolean fetched) {
		throw new UnsupportedOperationException( "CTE joins can not be treated" );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the treat from the CTE join and constrain the subtype inside the CTE body: declare the CTE over the subtype (`with emp as (select e from Employee e ...)`) or filter there with `where type(p) = SubType`.
  2. Apply TREAT to the real polymorphic entity join elsewhere in the query (attribute joins support treat) and have the CTE select from that treated root instead of treating the CTE join itself.
  3. If only subtype columns are needed, project them as plain columns in the CTE and drop the downcast at the join site.

Example fix

-- before: parser calls SqmCteJoin.treatAs(Class, String) -> UnsupportedOperationException
with people as (select p from Person p)
select t.salary from Client c
  join people p on p.id = c.id
  join treat(p as Employee) t on t.id = p.id

-- after: constrain the subtype inside the CTE; no treat on the CTE join
with employees as (select e from Employee e)
select e.salary from Client c
  join employees e on e.id = c.id
Defensive patterns

Strategy: type-guard

Validate before calling

// before applying any treat, verify the join actually models an entity type
import org.hibernate.query.sqm.tree.spi.from.*;

if ( join instanceof SqmCteJoin<?> ) {
    throw new IllegalArgumentException(
        "TREAT is unsupported on CTE joins; constrain the subtype inside the CTE definition" );
}

Type guard

import org.hibernate.query.sqm.tree.spi.from.*;

static boolean supportsTreatAs(Join<?, ?> join) {
    // CTE/derived/function joins are anonymous query shapes: no treat
    return !( join instanceof SqmCteJoin<?> )
        && !( join instanceof SqmDerivedJoin<?> )
        && !( join instanceof SqmFunctionJoin<?> );
}

Try / catch

try {
    JpaTreatedJoin<?, ?, ?> treated = ( (JpaJoin<?, ?>) join ).treatAs( Sub.class );
} catch ( UnsupportedOperationException e ) {
    if ( e.getMessage() != null && e.getMessage().contains( "can not be treated" ) ) {
        // query-shape bug, not transient: reject with context, never retry
        throw new IllegalArgumentException( "TREAT unsupported on join " + join.getAlias(), e );
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling treatAs(Class<S> treatJavaType, String alias) on a join whose SQM node is a SqmCteJoin: HQL `join treat(cteAlias as SubType) t on ...` (the HQL translator invokes the aliased overload), or SPI/criteria-translation code that holds the JpaJoin returned by root.join(JpaCteCriteria) and applies an aliased treat.

Common situations: Refactoring a polymorphic entity join into a CTE-based reporting query while keeping a TREAT call; generic query-DSL helpers that uniformly call treatAs(type, alias) on any Join; upgrading to Hibernate 7 where SQM join classes moved under org.hibernate.query.sqm.tree.spi.from and CTE joins now route to SqmCteJoin.

Related errors


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