hibernate/hibernate-orm · error · UnsupportedOperationException

Bags don't have indexes

Error message

Bags don't have indexes

What it means

getIndex supplies the index of an entry for indexed collections (ordered lists, maps). PersistentIdentifierBag implements it by throwing UnsupportedOperationException because identifier bags have no positional index - elements are identified by their collection id, not by position. The error means an index-dependent code path ran against an id-bag mapping.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentIdentifierBag.java:319

		}
		return deletes.iterator();
	}

	@Override
	public boolean hasDeletes(CollectionPersister persister) {
		final Map<?,?> snap = (Map<?,?>) getSnapshot();
		int deletes = snap.size();
		for ( E value : collection ) {
			if ( value != null ) {
				deletes --;
			}
		}
		return deletes > 0;
	}

	@Override
	public Object getIndex(Object entry, int i, CollectionPersister persister) {
		throw new UnsupportedOperationException("Bags don't have indexes");
	}

	@Override
	public Object getElement(Object entry) {
		return entry;
	}

	@Override
	public Object getSnapshotElement(Object entry, int i) {
		final Map<?,?> snap = (Map<?,?>) getSnapshot();
		final Object id = identifiers.get( i );
		return snap.get( id );
	}

	@Override
	public boolean needsInserting(Object entry, int i, Type elemType)
			throws HibernateException {
		final Map<?,?> snap = (Map<?,?>) getSnapshot();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use a genuinely indexed mapping (<list> / @OrderColumn on a List field) when index access is required
  2. Keep id-bag mappings for identifier-based semantics and drop positional logic
  3. Ensure field type and mapping kind match (List for indexed mappings)
  4. Clean rebuild to rule out stale mapping resources

Example fix

<!-- before -->
<id-bag name="items" table="order_item"> <!-- code expects indexes -->

<!-- after -->
<list name="items" table="order_item">
    <key column="order_id"/>
    <list-index column="position"/>
</list>
Defensive patterns

Strategy: validation

Validate before calling

CollectionPersister cp = sessionFactory.getDomainModel()
        .findCollectionDescriptor(Order.class.getName() + ".items");
if (cp == null || !cp.hasIndex()) {
    // id-bag: elements identified by collection id, not position; skip index logic
}

Type guard

static boolean isIndexedMapping(Field field) {
    return field.isAnnotationPresent(OrderColumn.class)
            || Map.class.isAssignableFrom(field.getType());
}

Prevention

When it happens

Trigger: Mapping metadata implying an index (order column / list semantics) while the runtime collection is an identifier bag; programmatic calls to PersistentCollection#getIndex; inconsistent mappings left behind by refactors between list and id-bag.

Common situations: Switching mappings between <list> and <id-bag> without updating all metadata; framework code driving the collection SPI; stale mappings after partial migration.

Related errors


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