hibernate/hibernate-orm · error · IllegalArgumentException

Passed attribute name [%s] did not correspond to a collectio

Error message

Passed attribute name [%s] did not correspond to a collection (bag) reference [%s] relative to %s

What it means

AbstractSqmFrom.joinCollection(attributeName, joinType) resolves the attribute via getSubPathSource(attributeName) and requires it to be a BagPersistentAttribute (a Collection/bag mapping). If the attribute exists but is a Set, List, Map or singular attribute, Hibernate throws IllegalArgumentException showing the attribute name, the resolved path source and the navigable path.

Source

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

		return joinCollection( attributeName, JoinType.INNER );
	}

	@Nonnull
	@Override
	@SuppressWarnings("unchecked")
	public <Y> SqmBagJoin<T, Y> joinCollection(@Nonnull String attributeName, @Nonnull JoinType jt) {
		final var joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName );
		if ( joinedPathSource instanceof BagPersistentAttribute ) {
			final var join = buildBagJoin(
					(BagPersistentAttribute<T, Y>) joinedPathSource,
					SqmJoinType.from( jt ),
					false
			);
			addSqmJoin( join );
			return join;
		}

		throw new IllegalArgumentException(
				String.format(
						Locale.ROOT,
						"Passed attribute name [%s] did not correspond to a collection (bag) reference [%s] relative to %s",
						attributeName,
						joinedPathSource,
						getNavigablePath()
				)
		);
	}

	@Nonnull
	@Override
	public <Y> SqmSetJoin<T, Y> joinSet(@Nonnull String attributeName) {
		return joinSet( attributeName, JoinType.INNER );
	}

	@Nonnull
	@Override

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use the join method matching the mapping: joinSet for Set, joinList for ordered List, joinMap for Map, join/join(entityType) for singular associations.
  2. Prefer the metamodel-typed overloads join(CollectionAttribute), join(SetAttribute), etc., which are compile-time safe.
  3. Check the attribute kind via the metamodel before choosing the join method in generic code.

Example fix

// before
SqmBagJoin<Customer, Order> o = customerRoot.joinCollection( "orders", JoinType.LEFT ); // orders is a Set
// after
SqmSetJoin<Customer, Order> o = customerRoot.joinSet( "orders", JoinType.LEFT );
Defensive patterns

Strategy: type-guard

Type guard

static boolean isBag(ManagedType<?> type, String attr) {
    return type.getAttribute( attr ) instanceof jakarta.persistence.metamodel.PluralAttribute<?, ?, ?> p
        && p.getCollectionType() == jakarta.persistence.metamodel.PluralAttribute.CollectionType.COLLECTION;
}

Prevention

When it happens

Trigger: root.joinCollection("orders", JoinType.INNER) when orders is mapped as java.util.Set, java.util.List (with @OrderColumn) or java.util.Map; joinCollection on a @ManyToOne/@Basic attribute.

Common situations: Changing an entity field from List to Set between versions while the query code still calls joinCollection; generic query helpers that always use joinCollection for any plural attribute; a List field mapped without @OrderColumn is a bag in Hibernate and works, but a Set field does not.

Related errors


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