hibernate/hibernate-orm · error · IllegalArgumentException
Not a treatable type: ${treatJavaType.getName()}
Error message
Not a treatable type: ${treatJavaType.getName()} What it means
SqmMapJoin.treatAs(Class, alias, fetch) downcasts a map join's value type V to a subtype S. It resolves the class via nodeBuilder().getDomainModel().managedType(treatJavaType) and requires the result to implement TreatableDomainType (entities and embeddables do); anything else - typically a @MappedSuperclass - throws IllegalArgumentException 'Not a treatable type: <FQCN>'. The sibling overload treatAs(EntityDomainType, alias, fetch) skips this check entirely because the metamodel type is already trusted.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmMapJoin.java:181
}
@Override
@Nonnull
public <S extends V> SqmTreatedMapJoin<L, K, V, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias) {
return treatAs( treatJavaType, alias, false );
}
@Override
@Nonnull
public <S extends V> SqmTreatedMapJoin<L, K, V, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias, boolean fetch) {
final var treatTarget = nodeBuilder().getDomainModel().managedType( treatJavaType );
final var treat = (SqmTreatedMapJoin<L, K, V, S>) findTreat( treatTarget, alias );
if ( treat == null ) {
if ( treatTarget instanceof TreatableDomainType<S> ) {
return addTreat( new SqmTreatedMapJoin<>( this, (SqmTreatableDomainType<S>) treatTarget, alias, fetch ) );
}
else {
throw new IllegalArgumentException( "Not a treatable type: " + treatJavaType.getName() );
}
}
else {
return treat;
}
}
@Nonnull
@Override
public <S extends V> SqmTreatedMapJoin<L, K, V, S> treatAs(@Nonnull EntityDomainType<S> treatTarget) {
return treatAs( treatTarget, null );
}
@Override
@Nonnull
public <S extends V> SqmTreatedMapJoin<L, K, V, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias, boolean fetch) {
final var treat = (SqmTreatedMapJoin<L, K, V, S>) findTreat( treatTarget, alias );
if ( treat == null ) {View on GitHub (pinned to fad1729dce)
Solutions
- Pass a concrete @Entity subtype of the map value type, e.g. mapJoin.treatAs(Cat.class)
- Prefer the type-safe overload: mapJoin.treatAs( metamodel.entity( Cat.class ) ) - it bypasses the class-resolution check
- Verify the treat target is annotated @Entity (not @MappedSuperclass) and is part of the same persistence unit
- If the hierarchy root is a @MappedSuperclass, treat directly to each concrete subclass used in the query
Example fix
// before - Animal is a @MappedSuperclass -> 'Not a treatable type: ...Animal'
SqmTreatedMapJoin<Person, String, Animal, Cat> tj = mapJoin.treatAs( Animal.class );
// after - treat to the concrete @Entity subtype
SqmTreatedMapJoin<Person, String, Animal, Cat> tj = mapJoin.treatAs( Cat.class );
// or, skipping class resolution entirely:
SqmTreatedMapJoin<Person, String, Animal, Cat> tj2 =
mapJoin.treatAs( metamodel.entity( Cat.class ) ); Defensive patterns
Strategy: validation
Validate before calling
import org.hibernate.metamodel.model.domain.TreatableDomainType;
ManagedType<?> candidate;
try {
candidate = entityManager.getMetamodel().managedType( treatClass );
} catch ( IllegalArgumentException e ) {
throw new IllegalArgumentException( "Not a managed type: " + treatClass.getName(), e );
}
if ( !(candidate instanceof TreatableDomainType<?>) ) {
throw new IllegalArgumentException(
"Not a treatable type (use a concrete @Entity subtype): " + treatClass.getName() );
}
return mapJoin.treatAs( treatClass ); Type guard
static boolean isTreatableTarget(jakarta.persistence.metamodel.Metamodel mm, Class<?> c) {
try {
return mm.managedType( c ) instanceof org.hibernate.metamodel.model.domain.TreatableDomainType<?>;
} catch ( IllegalArgumentException e ) {
return false; // not managed at all
}
} Try / catch
try {
join = mapJoin.treatAs( treatClass );
} catch ( IllegalArgumentException e ) {
if ( e.getMessage() != null && e.getMessage().startsWith( "Not a treatable type" ) ) {
throw new IllegalArgumentException( "Treat target " + treatClass.getName()
+ " is not an @Entity/@Embeddable in this persistence unit", e );
}
throw e;
} Prevention
- Only treat to concrete @Entity subtypes of the map value type
- Prefer treatAs(EntityDomainType) via metamodel.entity(Sub.class)
- Never treat to a @MappedSuperclass-annotated class
- Assert at startup that every treat target resolves to an entity in the persistence unit
- Beware same-simple-name imports of unmapped classes
When it happens
Trigger: Calling mapJoin.treatAs(SubType.class) or mapJoin(SubType.class) (HQL `join treat(x.map as Sub)` routes here too) where SubType resolves to a managed type that is not treatable - a @MappedSuperclass base class, or a class not mapped as @Entity/@Embeddable in this persistence unit.
Common situations: Treating a Map<String, Animal> join to Animal where Animal is a @MappedSuperclass rather than a mapped entity; wrong import using an identically named unmapped class; entity classes live in a module not included in the persistence unit; embeddable-valued maps treated against non-embeddable subtypes.
Related errors
- CTE joins can not be treated
- {mappedSuperclassTypeName} is not a supertype of {componentT
- Entity discriminator cannot be de-referenced
- Could not resolve entity class '{}'
- MappedSuperclassType cannot be used to create an SqmPath - t
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/5c5a344b2fe56cf9.
Report an issue: GitHub.