hibernate/hibernate-orm · error · PathException
Plural path '${getNavigablePath()}' refers to a collection a
Error message
Plural path '${getNavigablePath()}' refers to a collection and so element attribute '${name}' may not be referenced directly (use element() function) What it means
When an HQL/criteria path navigates through a plural attribute outside the FROM clause, SqmPluralValuedSimplePath.resolvePathPart only accepts the built-in collection-part names resolved by CollectionPart.Nature.fromNameExact (element/index forms). Any other continuation name means you are trying to read an attribute of the collection's *contents* directly from the collection reference, which Hibernate rejects with this PathException, telling you to go through element() instead.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmPluralValuedSimplePath.java:129
@Override
public @Nonnull JavaType<C> getJavaTypeDescriptor() {
return getPluralAttribute().getAttributeJavaType();
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitPluralValuedPath( this );
}
@Override
public SqmPath<?> resolvePathPart(
String name,
boolean isTerminal,
SqmCreationState creationState) {
// this is a reference to a collection outside the from clause
final var nature = CollectionPart.Nature.fromNameExact( name );
if ( nature == null ) {
throw new PathException( "Plural path '" + getNavigablePath()
+ "' refers to a collection and so element attribute '" + name
+ "' may not be referenced directly (use element() function)" );
}
final var sqmPath = get( name, true );
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
return sqmPath;
}
@Override
public SqmPath<?> resolveIndexedAccess(
SqmExpression<?> selector,
boolean isTerminal,
SqmCreationState creationState) {
final var pathRegistry = creationState.getCurrentProcessingState().getPathRegistry();
final String alias = selector.toHqlString();
final var navigablePath =
getParentNavigablePath()
.append( getNavigablePath().getLocalName(), alias )View on GitHub (pinned to fad1729dce)
Solutions
- Add an explicit join and reference its alias: 'from Order o join o.lines l where l.quantity > 5'
- Use the element() function to expose the collection contents: 'where element(o.lines).quantity > 5'
- Rewrite as a subquery when you must not change result cardinality: 'where exists (select 1 from o.lines l where l.quantity > 5)'
- If you expected a singular attribute, fix the mapping or the path: the attribute was mapped plural by mistake, or the wrong attribute name is used
Example fix
// before
List<Order> orders = session.createQuery(
"from Order o where o.lines.quantity > :min", Order.class)
.setParameter("min", 5).list();
// after
List<Order> orders = session.createQuery(
"from Order o join o.lines l where l.quantity > :min", Order.class)
.setParameter("min", 5).list(); Defensive patterns
Strategy: validation
Validate before calling
Attribute<?, ?> attr = managedType.getAttribute(parentName);
if (attr instanceof jakarta.persistence.metamodel.PluralAttribute) {
// must join (or use element()) before navigating to 'childName'
throw new IllegalArgumentException("Join required before " + parentName + "." + childName);
} Type guard
static boolean isPluralAttribute(ManagedType<?> type, String name) {
return type.getAttribute(name) instanceof jakarta.persistence.metamodel.PluralAttribute;
} Try / catch
try {
return session.createQuery(hql, type).list();
} catch (org.hibernate.query.PathException e) {
// rethrow with the offending fragment highlighted for query authors
throw new QueryBuildingException("Invalid path in: " + hql, e);
} Prevention
- Always join collections before referencing their elements' attributes in HQL
- For dynamically built HQL, lint every multi-segment path against the metamodel and reject segments crossing a PluralAttribute without a join
- Keep query tests on the same mapping as production so plural paths fail at build time
When it happens
Trigger: HQL like 'from Order o where o.lines.quantity > 5' where 'lines' is @OneToMany/@ManyToMany/@ElementCollection; 'select p.tags.label from Post p'; criteria code calling root.get("lines").get("quantity") across a plural attribute without a join.
Common situations: Porting SQL or JPQL written against a flattened schema; assuming Hibernate auto-creates implicit joins for every collection dereference; forgetting the join alias and re-navigating through the owner; upgrading Hibernate versions where previously accepted implicit collection paths now fail fast.
Related errors
- Could not interpret attribute '%s' of basic-valued path '%s'
- Cannot access the type of plural valued simple paths
- Cannot treat plural valued simple paths
- Entity discriminator cannot be de-referenced
- Entity discriminator cannot be de-referenced
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c3aad934ef5a2a44.
Report an issue: GitHub.