hibernate/hibernate-orm · error · IllegalArgumentException

Not a treatable type: {treatJavaType.getName()}

Error message

Not a treatable type: {treatJavaType.getName()}

What it means

SqmBagJoin.treatAs(Class, String alias, boolean fetch) (SqmBagJoin.java:161-173) resolves the passed class against the domain model via nodeBuilder().getDomainModel().managedType(treatJavaType) and requires the result to implement TreatableDomainType; entity types (and embeddable types in this codebase) implement it, while mapped-superclass types do not. When the class resolves to a managed but non-treatable type it throws IllegalArgumentException('Not a treatable type: <FQCN>') — the requested downcast target cannot be the right-hand side of a TREAT. All shorter Class-based overloads on SqmBagJoin (treat(Class), treatAs(Class), treatAs(Class, alias)) delegate to this method, so each fails identically; note the HQL 'treat(b as Sub)' route uses the EntityDomainType overload (line 175+) which does not perform this check.

Source

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

	}

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

	@Override
	@Nonnull
	public <S extends E> SqmTreatedBagJoin<O, E, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias, boolean fetch) {
		final var treatTarget = nodeBuilder().getDomainModel().managedType( treatJavaType );
		final var treat = (SqmTreatedBagJoin<O, E, S>) findTreat( treatTarget, alias );
		if ( treat == null ) {
			if ( treatTarget instanceof TreatableDomainType<?> ) {
				return addTreat( new SqmTreatedBagJoin<>( this, (SqmTreatableDomainType<S>) treatTarget, alias, fetch ) );
			}
			else {
				throw new IllegalArgumentException( "Not a treatable type: " + treatJavaType.getName() );
			}
		}
		return treat;
	}

	@Override
	@Nonnull
	public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias, boolean fetch) {
		final var treat = (SqmTreatedBagJoin<O, E, S>) findTreat( treatTarget, alias );
		if ( treat == null ) {
			return addTreat( new SqmTreatedBagJoin<>( this, (SqmEntityDomainType<S>) treatTarget, alias, fetch ) );
		}
		else {
			return treat;
		}
	}

}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Pass a concrete @Entity subtype of the element type as the treat target — mapped superclasses are not treatable because they have no table or discriminator.
  2. Validate first: resolve the target with domainModel.entity(SubType.class) or check managedType(...) instanceof TreatableDomainType before calling treatAs.
  3. If the abstract base must be a treat target, map it as an @Entity in the inheritance hierarchy (with an inheritance strategy) instead of @MappedSuperclass.
  4. Prefer the EntityDomainType overload treatAs(domainModel.entity(Sub.class), alias, fetch), which fails earlier and with a clearer error for wrong classes.

Example fix

// before - BaseLine is a @MappedSuperclass of order lines
ListJoin<Order, Line> lines = root.join(Order_.lines, JoinType.INNER);
lines.treat(BaseLine.class, "bl", false); // IllegalArgumentException: Not a treatable type: ...BaseLine

// after - treat to a concrete @Entity subtype
lines.treat(BookLine.class, "bl", false); // BookLine is an @Entity extending BaseLine
Defensive patterns

Strategy: validation

Validate before calling

import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.TreatableDomainType;

JpaMetamodel metamodel = sessionFactory.getDomainModel();
ManagedDomainType<?> target = metamodel.managedType(SubType.class);
if (!(target instanceof TreatableDomainType)) {
    throw new IllegalArgumentException(
        SubType.class.getName() + " is not treatable (must be an entity subtype, not a @MappedSuperclass)");
}
bagJoin.treatAs(SubType.class, "t", false);

Type guard

static boolean isTreatableType(JpaMetamodel metamodel, Class<?> candidate) {
    try {
        return metamodel.managedType(candidate) instanceof TreatableDomainType<?>;
    } catch (IllegalArgumentException e) {
        return false; // not a managed type at all
    }
}

Try / catch

try {
    join.treatAs(SubType.class, alias, fetch);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Not a treatable type")) {
        // treat target resolved to a non-treatable managed type (e.g. @MappedSuperclass)
        throw new QueryBuildException("TREAT target must be an @Entity subtype: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling bagJoin.treat(AbstractBase.class) / treatAs(...) on a List/Collection-valued join where AbstractBase is a @MappedSuperclass of the element type — managedType() resolves it to a MappedSuperclassDomainType which does not extend TreatableDomainType, so the check at line 165 fails. Also triggered by passing an embeddable class on Hibernate versions where EmbeddableDomainType is not treatable, or by generic frameworks accepting arbitrary Class tokens as treat targets. Only the Class-based overloads reach this line.

Common situations: Downcasting a @OneToMany List to a shared abstract base that is mapped as @MappedSuperclass instead of an @Entity hierarchy node; treating collections of embeddables; query frameworks that let callers pass any Class for treat; refactorings where a base class was annotated @MappedSuperclass and queries still treat to it.

Related errors


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