hibernate/hibernate-orm · error · UnsupportedOperationException

Cannot treat plural valued simple paths

Error message

Cannot treat plural valued simple paths

What it means

The TREAT operator downcasts a path to an entity subtype and is only defined for entity-valued paths. SqmPluralValuedSimplePath.treatAs(Class) throws UnsupportedOperationException because treating the collection reference itself, rather than one of its elements, has no defined semantics in the SQM model. The treat must be applied to a joined element or to element() of the plural path.

Source

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

		else {
			throw new NotIndexedCollectionException( "Index operator applied to path '" + getNavigablePath()
					+ "' which is not a list or map" );
		}
		join.setJoinPredicate( nodeBuilder().equal( index, selector ) );
		parent.addSqmJoin( join );
		return join;
	}

	@Nonnull
	@Override
	public SqmExpression<Class<? extends C>> type() {
		throw new UnsupportedOperationException( "Cannot access the type of plural valued simple paths" );
	}

	@Nonnull
	@Override
	public <S extends C> SqmTreatedPath<C, S> treatAs(@Nonnull Class<S> treatJavaType) {
		throw new UnsupportedOperationException( "Cannot treat plural valued simple paths" );
	}

	@Nonnull
	@Override
	public <S extends C> SqmTreatedEntityValuedSimplePath<C, S> treatAs(@Nonnull EntityDomainType<S> treatTarget) {
		throw new UnsupportedOperationException( "Cannot treat plural valued simple paths" );
	}

	@Nonnull
	@Override
	public SqmPredicate isEmpty() {
		return new SqmEmptinessPredicate( this, false, nodeBuilder() );
	}

	@Nonnull
	@Override
	public SqmPredicate isNotEmpty() {
		return new SqmEmptinessPredicate( this, true, nodeBuilder() );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Join the collection and treat the join alias in HQL: 'from Person p join treat(p.orders as SpecialOrder) so where so.bonus > 0'
  2. In criteria API, join first and treat the Join object: Join<Order,Order> o = p.join("orders"); Join<Order,SpecialOrder> t = cb.treat(o, SpecialOrder.class);
  3. Filter by type and join the subtype association separately: 'join p.orders so where type(so) = SpecialOrder and so.bonus > 0'
  4. If every element is the subtype, change the association target type in the mapping instead of treating at query time

Example fix

// before (HQL)
select p from Person p where treat(p.orders as SpecialOrder).bonus > 0

// after
select p from Person p join treat(p.orders as SpecialOrder) so where so.bonus > 0
Defensive patterns

Strategy: type-guard

Validate before calling

if (path.getReferencedPathSource() instanceof org.hibernate.metamodel.model.domain.PluralPersistentAttribute<?, ?, ?>) {
    throw new IllegalArgumentException("Join the collection before TREAT: " + path.getNavigablePath());
}

Type guard

static boolean isTreatable(SqmPath<?> path) {
    return !(path.getReferencedPathSource()
        instanceof org.hibernate.metamodel.model.domain.PluralPersistentAttribute<?, ?, ?>);
}

Try / catch

try {
    treated = builder.treat(path, SubType.class);
} catch (UnsupportedOperationException e) {
    // plural path: join first, then treat the Join object
}

Prevention

When it happens

Trigger: HQL 'treat(p.orders as SpecialOrder).bonus > 0' without joining 'orders' first; criteria code calling cb.treat(path.get("orders"), SpecialOrder.class) directly on a plural path; any treatAs(Class) invocation on a path resolved to a @OneToMany/@ManyToMany/@ElementCollection attribute.

Common situations: Polymorphic collections where a subtype-specific attribute must be filtered or selected; refactoring a query that used a join alias into inline navigation and forgetting the treat target changed; porting JPQL treat usage from entity paths to collection paths.

Related errors


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