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

  1. Add an explicit join and reference its alias: 'from Order o join o.lines l where l.quantity > 5'
  2. Use the element() function to expose the collection contents: 'where element(o.lines).quantity > 5'
  3. Rewrite as a subquery when you must not change result cardinality: 'where exists (select 1 from o.lines l where l.quantity > 5)'
  4. 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

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


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