{"record":{"id":"61a22e24c5adbb21","repo":"hibernate/hibernate-orm","slug":"sets-don-t-have-indexes","errorCode":null,"errorMessage":"Sets don't have indexes","messagePattern":"Sets don't have indexes","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentSet.java","lineNumber":411,"sourceCode":"\t\t// assuming the user implements equals() properly, as required by the Set\n\t\t// contract!\n\t\treturn oldValue == null && entry != null\n\t\t\t|| elemType.isDirty( oldValue, entry, getSession() );\n\t}\n\n\t@Override\n\tpublic boolean needsUpdating(Object entry, int i, Type elemType) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean isRowUpdatePossible() {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic Object getIndex(Object entry, int i, CollectionPersister persister) {\n\t\tthrow new UnsupportedOperationException(\"Sets don't have indexes\");\n\t}\n\n\t@Override\n\tpublic Object getElement(Object entry) {\n\t\treturn entry;\n\t}\n\n\t@Override\n\tpublic Object getSnapshotElement(Object entry, int i) {\n\t\tthrow new UnsupportedOperationException(\"Sets don't support updating by element\");\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"EqualsWhichDoesntCheckParameterClass\")\n\tpublic boolean equals(Object other) {\n\t\tread();\n\t\treturn set.equals( other );\n\t}","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentSet.java#L393-L429","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: Set field with indexed mapping\n@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)\n@OrderColumn(name = \"position\")\nprivate Set<Item> items = new HashSet<>();\n\n// after: pick one — indexed List, or unordered Set without index\n@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)\nprivate Set<Item> items = new HashSet<>();","handlingStrategy":"type-guard","validationCode":"if (attributeJavaType == java.util.Set.class && mappingDeclaresIndex(collectionMapping)) {\n    throw new IllegalStateException(\"Set attribute \" + attributeName + \" must not declare an index (@OrderColumn/@MapKeyColumn/<list>/<map>)\");\n}","typeGuard":"boolean canSupplyIndex(org.hibernate.collection.spi.PersistentCollection<?> collection) {\n    // sets are unordered and never carry an index\n    return !(collection instanceof org.hibernate.collection.spi.PersistentSet);\n}","tryCatchPattern":"try {\n    Object idx = persistentCollection.getIndex(entry, i, persister);\n} catch (UnsupportedOperationException e) {\n    throw new IllegalStateException(\"Indexed collection operation applied to a set-shaped collection; fix the mapping\", e);\n}","preventionTips":["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"],"tags":["hibernate","collections","mapping","persistent-set","index"],"backgroundTag":"collection-mapping-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}