hibernate/hibernate-orm · error · TreatException

Root path treats can not be aliased - " + getNavigablePath()

Error message

Root path treats can not be aliased - " + getNavigablePath().getFullPath()

What it means

SqmRoot.treatAs(EntityDomainType, alias, fetch) throws TreatException (a Hibernate SemanticException subclass) when a non-null alias is supplied. Treating a query root means narrowing the row type (TREAT(p AS Subtype)); the treated root shares the original root's identification variable, so giving it its own alias would create two aliases for one FROM element — SQL has no syntax for that. Hibernate therefore allows root treats only without alias.

Source

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

	}

	@Override
	@Nonnull
	public <S extends E> SqmTreatedFrom<E,E,S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias) {
		return treatAs( treatTarget, alias, false );
	}

	@Override
	@Nonnull
	public <S extends E> SqmTreatedFrom<E,E,S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias, boolean fetch) {
		return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch );
	}

	@Override
	@Nonnull
	public <S extends E> SqmTreatedFrom<E,E,S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias, boolean fetch) {
		if ( alias != null ) {
			throw new TreatException( "Root path treats can not be aliased - " + getNavigablePath().getFullPath() );
		}
		if ( fetch ) {
			throw new TreatException( "Root path treats can not be fetched - " + getNavigablePath().getFullPath() );
		}
		final var treat = findTreat( treatTarget, null );
		if ( treat == null ) {
			final var treatedRoot = new SqmTreatedRoot<>( this, (SqmEntityDomainType<S>) treatTarget );
			@SuppressWarnings("unchecked")
			final var typedTreat = (SqmTreatedFrom<E, E, S>) treatedRoot;
			return addTreat( typedTreat );
		}
		return treat;
	}

}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Call the single-argument overload `root.treatAs( Sub.class )` (alias defaults to null)
  2. Keep using the original root alias and qualify treat results through it, e.g. `select treat(p as Sub).specificAttr from Person p`
  3. If you need an independently-aliased subtype path, join an association and treat the join instead

Example fix

// before
JpaTreatedFrom<Person, Person, SpecialPerson> t = root.treatAs( SpecialPerson.class, "sp" ); // TreatException

// after
JpaTreatedFrom<Person, Person, SpecialPerson> t = root.treatAs( SpecialPerson.class );
Defensive patterns

Strategy: validation

Validate before calling

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

String aliasToUse = (root instanceof SqmRoot<?>) ? null : requestedAlias;
root.treatAs( Sub.class, aliasToUse ); // roots: always null alias

Try / catch

try {
    root.treatAs( Sub.class, alias );
} catch (org.hibernate.query.sqm.tree.spi.SqmTreasureNodeExceptionIgnoreMarker e) { throw e; }
// Prefer: catch org.hibernate.query.SemanticException at createQuery time
try { session.createQuery(hql).list(); }
catch (org.hibernate.query.SemanticException e) { /* report TreatException message */ }

Prevention

When it happens

Trigger: Criteria: `root.treatAs( Sub.class, "s" )` or `root.treatAs( subType, "s", false )`. HQL equivalents like `from Person p ... where treat(p as Sub).attr = ...` with an attempted `as s` on the treat. Also generic code that always passes an alias when calling the JPA treat overloads.

Common situations: Copy-pasting alias patterns from joined-path treats (which do accept aliases) onto root treats; wrapper APIs that generate an alias for every treated path; migrating JPA code where users assumed treatAs(Class, String) works everywhere because the signature is on JpaFrom.

Related errors


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