hibernate/hibernate-orm · error · UnsupportedOperationException

Setting a predicate for a plural part join is unsupported

Error message

Setting a predicate for a plural part join is unsupported

What it means

SqmPluralPartJoin is Hibernate's internal SQM node for joins that target a collection *part* (the pseudo-attributes exposed by a plural path, i.e. element()/index()/keys()). These joins are synthetic: Hibernate derives their join condition itself while building the query, so SqmPluralPartJoin.getJoinPredicate() always returns null and setJoinPredicate() unconditionally throws UnsupportedOperationException. Attaching a user-defined ON/WITH predicate to a collection-part join is therefore not supported by design.

Source

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

				)
		);
		copyTo( path, context );
		return path;
	}

	@Override
	public @Nonnull SqmFrom<?, O> getLhs() {
		return castNonNull( super.getLhs() );
	}

	@Override
	public @Nullable SqmPredicate getJoinPredicate() {
		return null;
	}

	@Override
	public void setJoinPredicate(@Nullable SqmPredicate predicate) {
		throw new UnsupportedOperationException( "Setting a predicate for a plural part join is unsupported" );
	}

	@Override
	public <X> X accept(SemanticQueryWalker<X> walker) {
		return walker.visitPluralPartJoin( this );
	}

	@Nonnull
	@Override
	public <S extends T> SqmTreatedPluralPartJoin<O, T, S> treatAs(@Nonnull Class<S> treatJavaType) {
		return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
	}

	@Nonnull
	@Override
	public <S extends T> SqmTreatedPluralPartJoin<O, T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget) {
		return treatAs( treatTarget, null );
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Move the restriction from the ON clause into the query's WHERE clause (for inner joins the result is equivalent)
  2. Join the plural attribute itself ('join p.nicknames n') instead of its element()/index() part, then apply on() to that SqmBagJoin/SqmSetJoin
  3. Replace the joined restriction with an EXISTS/IN subquery when the predicate must scope which elements are matched
  4. If a real ON predicate is genuinely required, remap the target as an entity association (@OneToMany over entities / @ManyToOne) instead of an @ElementCollection

Example fix

// before (HQL)
select n from Person p join p.nicknames.element n on n = 'Bob'

// after
select n from Person p join p.nicknames n where n = 'Bob'
Defensive patterns

Strategy: type-guard

Validate before calling

import org.hibernate.query.sqm.tree.spi.domain.SqmPluralPartJoin;

boolean supportsOn = !(join instanceof SqmPluralPartJoin);

Type guard

static boolean supportsOnPredicate(Join<?, ?> join) {
    return !(join instanceof org.hibernate.query.sqm.tree.spi.domain.SqmPluralPartJoin);
}

Try / catch

try {
    join.on(predicate);
} catch (UnsupportedOperationException e) {
    // plural-part join: move the restriction to the WHERE clause instead
    predicates.add(predicate);
}

Prevention

When it happens

Trigger: Calling jakarta.persistence.criteria.Join.on(Expression) or Join.on(String) on a Join whose referenced path source is a collection part obtained via element()/index()/keys(); HQL of the shape 'join p.nicknames.element n on ...'; any direct call to SqmJoin.setJoinPredicate(...) on an SqmPluralPartJoin instance.

Common situations: Migrating Hibernate 5 HQL that used 'with'/'on' clauses over collection elements; criteria API code that uniformly applies on() to every join it creates; switching an explicit attribute join to an element()/index() path and keeping the ON clause.

Related errors


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