hibernate/hibernate-orm · error · UnsupportedOperationException
Basic-value cannot be treated (downcast)
Error message
Basic-value cannot be treated (downcast)
What it means
SqmBasicValuedSimplePath.treatAs(Class) throws UnsupportedOperationException because TREAT (downcasting a path to a subclass) is only defined for entity-typed paths participating in an inheritance hierarchy. A basic-valued path (String, number, enum, converted object) has no subtype hierarchy, so no treat operation can exist. The exception is raised while the SQM tree is built, i.e. before SQL rendering.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmBasicValuedSimplePath.java:187
private @Nullable Class<?> getJavaTypeClass(SqmDomainType<T> sqmPathType) {
final SqmBindableType<T> expressible = nodeBuilder().resolveExpressible( sqmPathType );
return expressible == null ? null : expressible.getRelationalJavaType().getJavaTypeClass();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SqmPath
@Override
public @Nonnull BasicJavaType<T> getJavaTypeDescriptor() {
return (BasicJavaType<T>) super.getJavaTypeDescriptor();
}
@Nonnull
@Override
public <S extends T> SqmTreatedPath<T,S> treatAs(@Nonnull Class<S> treatJavaType) {
throw new UnsupportedOperationException( "Basic-value cannot be treated (downcast)" );
}
@Nonnull
@Override
public <S extends T> SqmTreatedPath<T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget) {
throw new UnsupportedOperationException( "Basic-value cannot be treated (downcast)" );
}
@Override
@Nonnull
public <S extends T> SqmTreatedPath<T, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias) {
throw new UnsupportedOperationException( "Basic-value cannot be treated (downcast)" );
}
@Override
@Nonnull
public <S extends T> SqmTreatedPath<T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias) {
throw new UnsupportedOperationException( "Basic-value cannot be treated (downcast)" );View on GitHub (pinned to fad1729dce)
Solutions
- Apply treat to the entity path instead: "treat(p as Brand)" or root.join("brand").treatAs(Brand.class), where brand is an association.
- If the value needs subtype handling, map it as an entity (@Entity with inheritance) or @Embeddable rather than basic + @Convert.
- Remove the treat and express the filter with a where condition or a type() predicate on the owning entity.
- Audit all TREAT usages after changing an attribute between basic and association mapping.
Example fix
// before - name is a basic String column -> UnsupportedOperationException
JpaPath<Brand> b = root.<String>get("name").treatAs(Brand.class);
// after - treat an actual entity association join
JpaJoin<Object, Brand> b = root.join("brand").treatAs(Brand.class); Defensive patterns
Strategy: type-guard
Validate before calling
// treat is legal only on entity-typed attributes
static boolean canTreat(jakarta.persistence.metamodel.ManagedType<?> owner, String attrName) {
return owner.getAttribute(attrName).getPersistentAttributeType()
== jakarta.persistence.metamodel.Attribute.PersistentAttributeType.ENTITY;
} Type guard
static boolean isEntityValued(jakarta.persistence.criteria.Path<?> path) {
return path.getJavaType() != null
&& jakarta.persistence.metamodel.EntityType.class.isAssignableFrom(path.getJavaType()) == false
? false
: true;
}
// Prefer the attribute check above; java type alone is not a reliable discriminator for treat. Try / catch
try {
JpaPath<Treated> t = (JpaPath<Treated>) base.treatAs(Treated.class);
} catch (UnsupportedOperationException e) {
throw new IllegalArgumentException("treat() applied to non-entity path " + base, e);
} Prevention
- Reserve TREAT for entity roots and association joins.
- In generic code, check PersistentAttributeType.ENTITY before emitting treat.
- Review TREAT usages whenever an association mapping is flattened to a basic column.
- Map value objects needing subtype behavior as entities, not @Convert basics.
When it happens
Trigger: HQL "select treat(p.name as Brand) from Person p" where p.name is a basic String attribute; Criteria code calling path.treatAs(SomeClass.class) on root.get("code") where code is basic; generic frameworks that call treatAs on every path implementing JpaPath; applying treat to an @Convert-mapped value object.
Common situations: A value class (e.g. BrandName) looks like an entity to the author but is persisted as a basic column via AttributeConverter; refactoring moved a related entity to a basic column (or vice versa) and old treat() queries still target it; query built by composing treat on an arbitrary join without checking its type; upgrading code that used treat only on entity joins to also treat attribute paths.
Related errors
- Cannot treat plural valued simple paths
- Entity discriminator cannot be de-referenced
- Could not resolve attribute '%s' of '%s' due to the attribut
- Cannot apply TREAT operator to discriminator path
- Non-aggregate composite paths cannot be TREAT-ed
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/02e155e252f65abe.
Report an issue: GitHub.