{"record":{"id":"9aa05c3c9a573d27","repo":"hibernate/hibernate-orm","slug":"bag-is-not-a-list","errorCode":null,"errorMessage":"Bag is not a list: ","messagePattern":"Bag is not a list: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentBag.java","lineNumber":94,"sourceCode":"\t *\n\t * @param session The session\n\t * @param coll The base elements.\n\t */\n\tpublic PersistentBag(SharedSessionContractImplementor session, Collection<E> coll) {\n\t\tsuper( session );\n\t\tsetCollection( coll );\n\t\tsetInitialized();\n\t\tsetDirectlyAccessible( true );\n\t}\n\n\tprivate void setCollection(Collection<E> bag) {\n\t\tthis.collection = bag;\n\t\tthis.bag = bag instanceof List<E> list ? list : null;\n\t}\n\n\tprotected List<E> bagAsList() {\n\t\tif ( bag == null ) {\n\t\t\tthrow new IllegalStateException( \"Bag is not a list: \" + collection.getClass().getName() );\n\t\t}\n\t\treturn bag;\n\t}\n\n\t@Override\n\tpublic boolean isWrapper(Object collection) {\n\t\treturn this.collection == collection;\n\t}\n\n\t@Override\n\tpublic boolean empty() {\n\t\treturn collection.isEmpty();\n\t}\n\n\t@Override\n\tpublic Iterator<E> entries(CollectionPersister persister) {\n\t\treturn collection.iterator();\n\t}","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentBag.java#L76-L112","documentation":"PersistentBag can wrap any java.util.Collection; list-position operations go through bagAsList(), which requires the wrapped collection to actually be a List. If the bag was built around a non-List collection (for example a HashSet the application placed in the field), any list-style operation such as add(index, e) or get(index) throws IllegalStateException naming the offending collection class. The mapping says bag, the runtime wrapper is not list-backed, and list operations are therefore impossible.","triggerScenarios":"A bag-mapped @OneToMany field declared as Collection but initialized with a non-List implementation (HashSet, ConcurrentLinkedQueue); Hibernate reuses the application-supplied collection when loading; later code casts or calls list operations (indexed add/get) on it.","commonSituations":"Bag-mapped collections initialized as new HashSet<>() by habit; switching collection implementations during refactoring; legacy <bag> mappings over set-like field types.","solutions":["Declare bag-mapped fields as List and initialize them with ArrayList so list operations stay valid","If set semantics are wanted, map the association as a Set (PersistentSet) instead of a bag","Never call indexed operations (get/add at index) on bag-mapped collections","Match field initialization to mapping semantics: List/ArrayList for bags and identifier bags"],"exampleFix":"// before\n@OneToMany(mappedBy = \"order\", cascade = CascadeType.ALL)\nprivate Collection<OrderLine> lines = new HashSet<>(); // bag wrapped around a Set -> bagAsList() throws\n\n// after\n@OneToMany(mappedBy = \"order\", cascade = CascadeType.ALL)\nprivate List<OrderLine> lines = new ArrayList<>();","handlingStrategy":"type-guard","validationCode":"// before any list-style call on a bag-mapped collection\nif (!(order.getLines() instanceof List)) {\n    throw new IllegalStateException(\n            \"lines is bag-mapped around a non-List collection; indexed access unsupported\");\n}","typeGuard":"static boolean supportsIndexAccess(Collection<?> collection) {\n    return collection instanceof List;\n}","tryCatchPattern":null,"preventionTips":["Initialize bag-mapped fields with ArrayList","Match field type to mapping semantics (List for bag/list, Set for set, Map for map)","Never cast persistent collections to List unless the mapping guarantees a List"],"tags":["hibernate","collection-mapping","bag","list","mapping-mismatch"],"backgroundTag":"bag-backed-by-non-list-collection","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}