{"record":{"id":"2af197441bb26a38","repo":"hibernate/hibernate-orm","slug":"bags-don-t-have-indexes-2af197","errorCode":null,"errorMessage":"Bags don't have indexes","messagePattern":"Bags don't have indexes","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentIdentifierBag.java","lineNumber":319,"sourceCode":"\t\t}\n\t\treturn deletes.iterator();\n\t}\n\n\t@Override\n\tpublic boolean hasDeletes(CollectionPersister persister) {\n\t\tfinal Map<?,?> snap = (Map<?,?>) getSnapshot();\n\t\tint deletes = snap.size();\n\t\tfor ( E value : collection ) {\n\t\t\tif ( value != null ) {\n\t\t\t\tdeletes --;\n\t\t\t}\n\t\t}\n\t\treturn deletes > 0;\n\t}\n\n\t@Override\n\tpublic Object getIndex(Object entry, int i, CollectionPersister persister) {\n\t\tthrow new UnsupportedOperationException(\"Bags 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\tfinal Map<?,?> snap = (Map<?,?>) getSnapshot();\n\t\tfinal Object id = identifiers.get( i );\n\t\treturn snap.get( id );\n\t}\n\n\t@Override\n\tpublic boolean needsInserting(Object entry, int i, Type elemType)\n\t\t\tthrows HibernateException {\n\t\tfinal Map<?,?> snap = (Map<?,?>) getSnapshot();","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentIdentifierBag.java#L301-L337","documentation":"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.","triggerScenarios":"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.","commonSituations":"Switching mappings between <list> and <id-bag> without updating all metadata; framework code driving the collection SPI; stale mappings after partial migration.","solutions":["Use a genuinely indexed mapping (<list> / @OrderColumn on a List field) when index access is required","Keep id-bag mappings for identifier-based semantics and drop positional logic","Ensure field type and mapping kind match (List for indexed mappings)","Clean rebuild to rule out stale mapping resources"],"exampleFix":"<!-- before -->\n<id-bag name=\"items\" table=\"order_item\"> <!-- code expects indexes -->\n\n<!-- after -->\n<list name=\"items\" table=\"order_item\">\n    <key column=\"order_id\"/>\n    <list-index column=\"position\"/>\n</list>","handlingStrategy":"validation","validationCode":"CollectionPersister cp = sessionFactory.getDomainModel()\n        .findCollectionDescriptor(Order.class.getName() + \".items\");\nif (cp == null || !cp.hasIndex()) {\n    // id-bag: elements identified by collection id, not position; skip index logic\n}","typeGuard":"static boolean isIndexedMapping(Field field) {\n    return field.isAnnotationPresent(OrderColumn.class)\n            || Map.class.isAssignableFrom(field.getType());\n}","tryCatchPattern":null,"preventionTips":["Choose <list>/@OrderColumn mappings when positional access is required","Keep id-bag mappings free of index-based logic","Clean rebuild after switching collection mapping kinds to avoid stale metadata"],"tags":["hibernate","collection-mapping","id-bag","index","unsupported-operation"],"backgroundTag":"indexed-access-on-bag","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}