hibernate/hibernate-orm · error · NotIndexedCollectionException

Index operator applied to path '${getNavigablePath()}' which

Error message

Index operator applied to path '${getNavigablePath()}' which is not a list or map

What it means

The HQL index operator 'path[selector]' is only defined for indexed collections. SqmPluralValuedSimplePath.resolveIndexedAccess handles exactly two shapes: a ListPersistentAttribute (selector compared to the list position) and a MapPersistentAttribute (selector compared to the key), building a join with an equality predicate on the index/key. For any other plural attribute (Set, bag/Collection, @ElementCollection without index) there is nothing to compare the selector against, so it throws org.hibernate.query.NotIndexedCollectionException.

Source

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

					SqmJoinType.INNER,
					false,
					nodeBuilder()
			);
			index = ( (SqmListJoin<?, ?>) join).index();
		}
		else if ( referencedPathSource instanceof MapPersistentAttribute<?, ?, ?> ) {
			join = new SqmMapJoin<>(
					parent,
					(SqmMapPersistentAttribute<P, ?, ?>) referencedPathSource,
					alias,
					SqmJoinType.INNER,
					false,
					nodeBuilder()
			);
			index = ( (SqmMapJoin<?, ?, ?>) join).key();
		}
		else {
			throw new NotIndexedCollectionException( "Index operator applied to path '" + getNavigablePath()
					+ "' which is not a list or map" );
		}
		join.setJoinPredicate( nodeBuilder().equal( index, selector ) );
		parent.addSqmJoin( join );
		return join;
	}

	@Nonnull
	@Override
	public SqmExpression<Class<? extends C>> type() {
		throw new UnsupportedOperationException( "Cannot access the type of plural valued simple paths" );
	}

	@Nonnull
	@Override
	public <S extends C> SqmTreatedPath<C, S> treatAs(@Nonnull Class<S> treatJavaType) {
		throw new UnsupportedOperationException( "Cannot treat plural valued simple paths" );
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Rewrite the access as an explicit join with a WHERE on the distinguishing property: 'join p.phones ph where ph.type = "home"'
  2. If positional access is required, remap as an ordered List with @OrderColumn so 'p.items[0]' is legal
  3. If keyed access is required, remap as a Map with @MapKey/@MapKeyColumn and use 'p.phones["home"]'
  4. For bag semantics, filter with a subquery instead of indexing

Example fix

// before: phones mapped as Set<Phone>; HQL uses a key
// select p from Person p where p.phones['home'].number = '555-1234'

// after: join and filter on the discriminator-like property
select p from Person p join p.phones ph where ph.type = 'home' and ph.number = '555-1234'

// alternative: remap as a Map so indexing is valid
@OneToMany(mappedBy = "person")
@MapKeyColumn(name = "phone_type")
Map<String, Phone> phones;
Defensive patterns

Strategy: type-guard

Validate before calling

Attribute<?, ?> a = managedType.getAttribute(attrName);
boolean indexable = a instanceof jakarta.persistence.metamodel.ListAttribute<?, ?>
    || a instanceof jakarta.persistence.metamodel.MapAttribute<?, ?, ?>;
if (!indexable) throw new IllegalArgumentException(attrName + " is not a List or Map; [ ] access invalid");

Type guard

static boolean supportsIndexOperator(ManagedType<?> type, String attr) {
    Attribute<?, ?> a = type.getAttribute(attr);
    return a instanceof jakarta.persistence.metamodel.ListAttribute<?, ?>
        || a instanceof jakarta.persistence.metamodel.MapAttribute<?, ?, ?>;
}

Try / catch

try {
    return session.createQuery(hql, type).singleResult();
} catch (org.hibernate.query.NotIndexedCollectionException e) {
    // rewrite as join + where on the position/key property instead
}

Prevention

When it happens

Trigger: HQL 'o.items[0]' or 'p.phones["home"]' where the attribute is a Set<?> or Collection<?>; criteria/SPI indexed access (resolveIndexedAccess) on a non-indexed plural path; mapping the field as Set while the query was written for a List or Map.

Common situations: Changing a field between List/Set/Map without updating queries; adding @ElementCollection as a Set but writing positional access; assuming @OrderColumn exists when the collection was mapped unordered.

Related errors


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