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

  1. Apply treat to the entity path instead: "treat(p as Brand)" or root.join("brand").treatAs(Brand.class), where brand is an association.
  2. If the value needs subtype handling, map it as an entity (@Entity with inheritance) or @Embeddable rather than basic + @Convert.
  3. Remove the treat and express the filter with a where condition or a type() predicate on the owning entity.
  4. 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

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


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