hibernate/hibernate-orm · error · UnsupportedOperationException
Sets don't support updating by element
Error message
Sets don't support updating by element
What it means
PersistentCollection.getSnapshotElement(entry, i) supplies the element's snapshot state used to decide whether an existing row needs an UPDATE. PersistentSet explicitly reports isRowUpdatePossible() == false — set rows are deleted and re-inserted, never updated — so it cannot provide snapshot elements and throws when asked. Getting here means dirty-check/flush logic (or custom code) expects row updates on a set, the same mapping-mismatch family as getIndex.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentSet.java:421
@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 );
}
@Override
public int hashCode() {
read();
return set.hashCode();
}
@Override
public boolean entryExists(Object key, int i) {
return key != null;View on GitHub (pinned to fad1729dce)
Solutions
- Make the mapping match set semantics: plain @OneToMany Set / <set>, no index or update-oriented metadata
- If elements really are updated in place, map the association as a List/Map or a component collection that supports row updates
- Search for custom code calling getSnapshotElement/isRowUpdatePossible on PersistentSet and branch on collection kind
- Re-run schema/mapping validation (SessionFactory boot) after every collection type change
Example fix
// before: Set treated as updatable/indexed collection @OneToMany @OrderColumn(name = "pos") private Set<Item> items = new HashSet<>(); // after: unordered set, delete-and-reinsert semantics @OneToMany private Set<Item> items = new HashSet<>();
Defensive patterns
Strategy: type-guard
Validate before calling
if (persistentCollection instanceof org.hibernate.collection.spi.PersistentSet && codePathExpectsRowUpdates()) {
throw new IllegalStateException("Sets use delete+insert semantics; row updates are not possible");
} Type guard
boolean supportsRowUpdates(org.hibernate.collection.spi.PersistentCollection<?> collection) {
return !(collection instanceof org.hibernate.collection.spi.PersistentSet); // isRowUpdatePossible() == false
} Try / catch
try {
Object snap = collection.getSnapshotElement(entry, i);
} catch (UnsupportedOperationException e) {
// set semantics: compare whole collection, not per-row updates
rebuildFromScratch(collection);
} Prevention
- Treat set collections as delete+insert in custom flush/copy logic
- Align mapping with collection semantics and re-boot the factory after changes
- Prefer List/Map or embeddable-element mappings when in-place row updates are required
When it happens
Trigger: A persister or custom code path performing per-element snapshot comparison against a PersistentSet: typically a mapping that implies updatable/indexed collection semantics applied to a Set attribute, or direct internal API calls on the PersistentSet instance.
Common situations: Same drift as 'Sets don't have indexes': index or update-oriented metadata left on a field that became a Set; custom collection persisters assuming row updates; copying collections between persistent contexts with mismatched semantics.
Related errors
- Sets don't have indexes
- cannot recreate collection while filter is enabled: " + coll
- cannot recreate collection while filter is enabled [%s : %s]
- queued clear cannot be used with orphan delete
- The INSERT statement for table [%s] contains no column, and
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/a8501977253f55e0.
Report an issue: GitHub.