hibernate/hibernate-orm · error · UnsupportedOperationException

Derived roots can not be treated

Error message

Derived roots can not be treated

What it means

SqmDerivedRoot.treatAs throws UnsupportedOperationException: TREAT requires an entity inheritance hierarchy, but a derived root denotes subquery rows with no persistent type hierarchy, so downcasting it is meaningless. This is the derived-root counterpart of the basic-path treat failures. The exception is thrown while the SQM tree is built, before SQL rendering.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmDerivedRoot.java:116

	public String getEntityName() {
		throw new UnsupportedOperationException( "Derived root does not have an entity type. Use getReferencedPathSource() instead." );
	}

	@Override
	public SqmPathSource<T> getResolvedModel() {
		return getReferencedPathSource();
	}

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

	@Override
	@Nonnull
	public <S extends T> SqmTreatedFrom<T, T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias, boolean fetch) {
		throw new UnsupportedOperationException( "Derived roots can not be treated" );
	}

	@Override
	public boolean deepEquals(SqmFrom<?, ?> object) {
		return super.deepEquals( object )
			&& subQuery.equals( ((SqmDerivedRoot<?>) object).subQuery );
	}

	@Override
	public boolean isDeepCompatible(SqmFrom<?, ?> object) {
		return super.isDeepCompatible( object )
			&& subQuery.isCompatible( ((SqmDerivedRoot<?>) object).subQuery );
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Apply TREAT inside the inner subquery before deriving: "from (select treat(e as Manager) m from Employee e) t" select m.bonus from t.
  2. Or treat the entity root directly in an ordinary query and push filtering into a where clause instead of a derived table.
  3. If only subclass rows matter, filter with a type() predicate in the inner select: "select e from Employee e where type(e) = Manager".
  4. Avoid treatAs on any root that is not a plain SqmRoot/SqmEntityJoin.

Example fix

// before - derived root cannot be treated
"select treat(t as Manager).bonus from (select e from Employee e) t"

// after - treat inside the derived subquery first
"select t.bonus from (select treat(e as Manager) as m from Employee e where type(e) = Manager) t"
Defensive patterns

Strategy: type-guard

Validate before calling

// Only emit TREAT when the treated node is a plain entity root/join
static boolean treatableRoot(Object node) {
    return node instanceof org.hibernate.query.sqm.tree.spi.from.SqmRoot
        || node instanceof org.hibernate.query.sqm.tree.spi.from.SqmEntityJoin
        || node instanceof org.hibernate.query.sqm.tree.spi.from.SqmCrossJoin;
    // note: SqmDerivedRoot, SqmCteRoot, SqmCorrelatedDerivedRoot throw on treatAs
}

Type guard

static boolean isDerivedRoot(Object node) {
    return node instanceof org.hibernate.query.sqm.tree.spi.domain.SqmDerivedRoot;
}

Try / catch

try {
    root.treatAs(target, alias, fetch);
} catch (UnsupportedOperationException e) {
    throw new IllegalArgumentException("TREAT is not supported on derived roots; move treat into the inner subquery", e);
}

Prevention

When it happens

Trigger: HQL "select treat(t as Manager).bonus from (select e from Employee e) t"; criteria code calling derivedRoot.treatAs(Manager.class) on a root created for a from-subquery; copy of entity-root treat patterns applied to derived roots.

Common situations: Queries rewritten over derived tables (for window functions, row limiting) that kept TREAT from the original entity query; migration from Blaze-Persistence where treating subselect aliases behaved differently; assumption that "from (select e from Employee e)" preserves treatability of e.

Related errors


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