hibernate/hibernate-orm · error · TreatException

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

Error message

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

What it means

SqmRoot.treatAs(EntityDomainType, alias, fetch) throws TreatException when fetch=true. A root treat is a type-narrowing expression, not a fetch graph element: SQL TREAT does not fetch anything itself, and Hibernate cannot generate fetch joins for a virtual treated root on top of the existing root row. Root treats are only valid as unaliased, unfetched path sources; fetching must be expressed as explicit fetch joins.

Source

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

	@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. Use `root.treatAs( Sub.class )` without fetch, and add explicit fetch joins on the treated path: `join fetch p.subAttr`
  2. Move the fetch to an association join and treat that join: `join p.related r fetch` + `treat(r as Sub)`
  3. Select the subtype attributes you need instead of fetching them
  4. Restructure the query as a subtype-targeted query (`from SpecialPerson`) when you only want that subtype with its associations

Example fix

// before (HQL: root treat + fetch)
List<Person> l = session.createQuery("from Person p join fetch treat(p as SpecialPerson).bonus", Person.class).list();

// after
List<SpecialPerson> l = session.createQuery("from SpecialPerson s join fetch s.bonus", SpecialPerson.class).list();
Defensive patterns

Strategy: validation

Validate before calling

boolean fetched = false; // root treats can never be fetched
root.treatAs( Sub.class, null, fetched );
// or simply: root.treatAs( Sub.class );

Prevention

When it happens

Trigger: Criteria: `root.treatAs( Sub.class, null, true )` — the three-arg overload with fetched=true. HQL constructs that translate to a fetched root treat, e.g. `join fetch treat(p as Sub).attr` on a root, which sets the fetched flag on SqmRoot.treatAs. Generic code that always passes fetched=true.

Common situations: Trying to combine TREAT with JOIN FETCH at the root level (`from Person p join fetch treat(p as Sub).specialAttr`); building generic fetch-graph resolvers that mark every treated path as fetched; upgrading from older Hibernate versions where this pattern was silently accepted or failed later.

Related errors


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