hibernate/hibernate-orm · error · UnsupportedOperationException

Derived joins can not be treated

Error message

Derived joins can not be treated

What it means

SqmDerivedJoin models a join to a subquery result: HQL `join (select ...) d on ...`, criteria `JpaFrom.join(Subquery)` / `joinLateral(...)`. The joined thing is an anonymous query result, not a metamodel entity type — SqmDerivedJoin.getAttribute() returns null — so there is no inheritance hierarchy to downcast. Every treatAs overload, including this public criteria-facing treatAs(Class<S>), throws UnsupportedOperationException at query-construction time.

Source

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

	@Override
	public <X> X accept(SemanticQueryWalker<X> walker) {
		return walker.visitQualifiedDerivedJoin( this );
	}

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

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

	@Nonnull
	@Override
	public <S extends T> SqmTreatedJoin<T, T, S> treatAs(@Nonnull Class<S> treatTarget) {
		throw new UnsupportedOperationException( "Derived joins can not be treated" );
	}

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

	@Override
	@Nonnull
	public <S extends T> SqmTreatedJoin<T, T, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias) {
		throw new UnsupportedOperationException( "Derived 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( "Derived joins can not be treated" );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the treatAs and make the subquery select the concrete subtype (`select m from Manager m ...`) so the derived join is already correctly typed.
  2. Join the target entity directly with an attribute/entity join (where treat is supported) and express the correlation via on/where predicates instead of joining the subquery result.
  3. In dynamic query builders, branch on the join kind (skip treat for JpaDerivedJoin) instead of calling treatAs unconditionally.

Example fix

// before - UnsupportedOperationException: Derived joins can not be treated
JpaDerivedJoin<Employee> d = root.join( employeesSubquery );
d.treatAs( Manager.class );

// after - the subquery selects Manager, so the derived join needs no downcast
JpaSubQuery<Manager> managerSub = query.subquery( Manager.class );
JpaRoot<Manager> m = managerSub.from( Manager.class );
managerSub.select( m ).where( cb.equal( m.get( "department" ), root.get( "department" ) ) );
JpaDerivedJoin<Manager> d = root.join( managerSub );
Defensive patterns

Strategy: type-guard

Validate before calling

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

if ( join instanceof SqmDerivedJoin<?> ) {
    throw new IllegalArgumentException(
        "TREAT is unsupported on derived (subquery) joins; select the subtype inside the subquery" );
}

Type guard

static boolean supportsTreat(Join<?, ?> join) {
    // derived joins are anonymous result shapes - only attribute/roots can be treated
    return !( join instanceof SqmDerivedJoin<?> )
        && !( join instanceof SqmCteJoin<?> )
        && !( join instanceof SqmFunctionJoin<?> );
}

Try / catch

try {
    treated = ( (JpaJoin<?, ?>) join ).treatAs( Sub.class );
} catch ( UnsupportedOperationException e ) {
    if ( e.getMessage() != null && e.getMessage().contains( "Derived joins" ) ) {
        throw new QueryConstructionException(
            "TREAT unsupported on derived join " + join.getAlias()
                + "; type the subquery result instead", e );
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling treatAs(Class) on a JpaDerivedJoin: `JpaDerivedJoin<Employee> d = root.join(subquery); d.treatAs(Manager.class);` — or an HQL treat path expression over a derived-join alias such as `treat(d as Manager).salary`.

Common situations: Replacing an entity attribute join with a subquery join (dedup, limits, aggregates) while keeping a TREAT from the old query; generic criteria wrappers that call treatAs(Class) on arbitrary joins; Hibernate 6.x to 7 migration moving these classes to the spi.from package.

Related errors


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