hibernate/hibernate-orm · error · UnsupportedOperationException
Sets don't have indexes
Error message
Sets don't have indexes
What it means
PersistentCollection.getIndex(entry, i, persister) returns the collection index (list position or map key) that indexed collection persisters use when writing rows. PersistentSet implements it by throwing because a set is unordered and persisted as plain element rows with no index. Reaching this method means code or a persister that expects an indexed collection is operating on a set-shaped PersistentCollection — almost always a mapping/Java type mismatch.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentSet.java:411
// assuming the user implements equals() properly, as required by the Set
// contract!
return oldValue == null && entry != null
|| elemType.isDirty( oldValue, entry, getSession() );
}
@Override
public boolean needsUpdating(Object entry, int i, Type elemType) {
return false;
}
@Override
public boolean isRowUpdatePossible() {
return false;
}
@Override
public Object getIndex(Object entry, int i, CollectionPersister persister) {
throw new UnsupportedOperationException("Sets don't have indexes");
}
@Override
public Object getElement(Object entry) {
return entry;
}
@Override
public Object getSnapshotElement(Object entry, int i) {
throw new UnsupportedOperationException("Sets don't support updating by element");
}
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object other) {
read();
return set.equals( other );
}View on GitHub (pinned to fad1729dce)
Solutions
- Align the Java type with the mapping: Set fields must use plain @OneToMany (no @OrderColumn/@MapKeyColumn) or <set>
- If the field is now a Set, delete the index metadata (@OrderColumn, @MapKeyColumn, <list-index>, <index>)
- Audit both annotations and any .hbm.xml for the same collection role after type changes
- In custom persister/collection code, never call getIndex on a PersistentSet — branch on collection kind first
Example fix
// before: Set field with indexed mapping @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @OrderColumn(name = "position") private Set<Item> items = new HashSet<>(); // after: pick one — indexed List, or unordered Set without index @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) private Set<Item> items = new HashSet<>();
Defensive patterns
Strategy: type-guard
Validate before calling
if (attributeJavaType == java.util.Set.class && mappingDeclaresIndex(collectionMapping)) {
throw new IllegalStateException("Set attribute " + attributeName + " must not declare an index (@OrderColumn/@MapKeyColumn/<list>/<map>)");
} Type guard
boolean canSupplyIndex(org.hibernate.collection.spi.PersistentCollection<?> collection) {
// sets are unordered and never carry an index
return !(collection instanceof org.hibernate.collection.spi.PersistentSet);
} Try / catch
try {
Object idx = persistentCollection.getIndex(entry, i, persister);
} catch (UnsupportedOperationException e) {
throw new IllegalStateException("Indexed collection operation applied to a set-shaped collection; fix the mapping", e);
} Prevention
- Keep the Java collection type and mapping metadata in sync (Set <-> no index, List/Map <-> index)
- Re-validate mappings (boot the SessionFactory) after every List<->Set refactor
- Never call PersistentCollection index APIs on a PersistentSet
When it happens
Trigger: A mapping declares an index (@OrderColumn/@ListIndex/@MapKeyColumn, <list>/<map> with <index>/<list-index>) but the Java attribute is a java.util.Set (PersistentSet); refactoring a field from List to Set while keeping the index metadata; custom persisters or metamodel/collection-copy code calling getIndex on a PersistentSet.
Common situations: Changing List to Set to fix duplicate-element bugs without updating annotations; .hbm.xml left with <list> after the field type changed; mixed annotation+hbm configuration of the same collection role; custom CollectionType implementations reusing set collections.
Related errors
- Sets don't support updating by element
- cannot recreate collection while filter is enabled: " + coll
- cannot recreate collection while filter is enabled [%s : %s]
- negative index
- queued clear cannot be used with orphan delete
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/61a22e24c5adbb21.
Report an issue: GitHub.