{"record":{"id":"3e605de3eaf95348","repo":"hibernate/hibernate-orm","slug":"setting-a-predicate-for-a-plural-part-join-is-unsu","errorCode":null,"errorMessage":"Setting a predicate for a plural part join is unsupported","messagePattern":"Setting a predicate for a plural part join is unsupported","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmPluralPartJoin.java","lineNumber":102,"sourceCode":"\t\t\t\t)\n\t\t);\n\t\tcopyTo( path, context );\n\t\treturn path;\n\t}\n\n\t@Override\n\tpublic @Nonnull SqmFrom<?, O> getLhs() {\n\t\treturn castNonNull( super.getLhs() );\n\t}\n\n\t@Override\n\tpublic @Nullable SqmPredicate getJoinPredicate() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void setJoinPredicate(@Nullable SqmPredicate predicate) {\n\t\tthrow new UnsupportedOperationException( \"Setting a predicate for a plural part join is unsupported\" );\n\t}\n\n\t@Override\n\tpublic <X> X accept(SemanticQueryWalker<X> walker) {\n\t\treturn walker.visitPluralPartJoin( this );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic <S extends T> SqmTreatedPluralPartJoin<O, T, S> treatAs(@Nonnull Class<S> treatJavaType) {\n\t\treturn treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic <S extends T> SqmTreatedPluralPartJoin<O, T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget) {\n\t\treturn treatAs( treatTarget, null );\n\t}","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmPluralPartJoin.java#L84-L120","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Move the restriction from the ON clause into the query's WHERE clause (for inner joins the result is equivalent)","Join the plural attribute itself ('join p.nicknames n') instead of its element()/index() part, then apply on() to that SqmBagJoin/SqmSetJoin","Replace the joined restriction with an EXISTS/IN subquery when the predicate must scope which elements are matched","If a real ON predicate is genuinely required, remap the target as an entity association (@OneToMany over entities / @ManyToOne) instead of an @ElementCollection"],"exampleFix":"// before (HQL)\nselect n from Person p join p.nicknames.element n on n = 'Bob'\n\n// after\nselect n from Person p join p.nicknames n where n = 'Bob'","handlingStrategy":"type-guard","validationCode":"import org.hibernate.query.sqm.tree.spi.domain.SqmPluralPartJoin;\n\nboolean supportsOn = !(join instanceof SqmPluralPartJoin);","typeGuard":"static boolean supportsOnPredicate(Join<?, ?> join) {\n    return !(join instanceof org.hibernate.query.sqm.tree.spi.domain.SqmPluralPartJoin);\n}","tryCatchPattern":"try {\n    join.on(predicate);\n} catch (UnsupportedOperationException e) {\n    // plural-part join: move the restriction to the WHERE clause instead\n    predicates.add(predicate);\n}","preventionTips":["Apply ON/WITH clauses only to entity-association joins, never to element()/index()/keys() paths","Prefer WHERE restrictions over ON when joining element collections","In generic join-building code, test the SqmJoin type before calling on()"],"tags":["hibernate","sqm","hql","criteria-api","join","on-clause","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}