hibernate/hibernate-orm · error · IllegalStateException
Bag is not a list:
Error message
Bag is not a list:
What it means
PersistentIdentifierBag (id-bag mapping) wraps any java.util.Collection; list-position operations go through bagAsList(), which only works when the wrapped collection is a List. If the id-bag was constructed around a non-List collection, list-style operations throw IllegalStateException with the collection's class name. As with PersistentBag, the runtime collection type does not support the list operations being attempted.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentIdentifierBag.java:99
* @param session The session
* @param coll The base elements
*/
public PersistentIdentifierBag(SharedSessionContractImplementor session, Collection<E> coll) {
super( session );
setCollection( coll );
setInitialized();
setDirectlyAccessible( true );
identifiers = new HashMap<>();
}
private void setCollection(Collection<E> bag) {
this.collection = bag;
this.values = bag instanceof List<E> list ? list : null;
}
protected List<E> bagAsList() {
if ( values == null ) {
throw new IllegalStateException( "Bag is not a list: " + collection.getClass().getName() );
}
return values;
}
@Override
public void initializeFromCache(CollectionPersister persister, Object disassembled, Object owner)
throws HibernateException {
final Serializable[] array = (Serializable[]) disassembled;
final int size = array.length;
assert identifiers == null;
assert collection == null;
identifiers = new HashMap<>();
//noinspection unchecked
setCollection( (Collection<E>) persister.getCollectionSemantics().instantiateRaw( size, persister ) );
for ( int i = 0; i < size; i+=2 ) {View on GitHub (pinned to fad1729dce)
Solutions
- Declare the field as List and initialize with ArrayList for id-bag mappings
- Map set-like fields as Set instead of id-bag if set semantics are intended
- Avoid positional operations on identifier bags
- Add a convention check/test that bag and id-bag fields are initialized with ArrayList
Example fix
// before @org.hibernate.annotations.CollectionId /* id-bag style mapping */ private Collection<Tag> tags = new HashSet<>(); // non-List backing -> bagAsList() throws // after @org.hibernate.annotations.CollectionId /* id-bag style mapping */ private List<Tag> tags = new ArrayList<>();
Defensive patterns
Strategy: type-guard
Validate before calling
if (!(order.getTags() instanceof List)) {
throw new IllegalStateException(
"tags is id-bag mapped around a non-List collection; use ArrayList");
} Type guard
static boolean supportsIndexAccess(Collection<?> collection) {
return collection instanceof List;
} Prevention
- Initialize id-bag mapped fields with ArrayList
- Map set-like fields as Set rather than id-bag
- Add a convention test that bag/id-bag fields are List-typed with ArrayList initializers
When it happens
Trigger: An id-bag mapped field (collection with <id-bag> or identifier-bag semantics) whose application-initialized value is a non-List Collection such as a HashSet; then indexed add/get or list-snapshot paths run against it.
Common situations: Fields initialized with HashSet or custom Collection implementations under id-bag mappings; refactors that changed the field initializer but kept the mapping; copy-pasted initializers across entity classes.
Related errors
- Bag is not a list:
- Bags don't have indexes
- Duplicate collection definition '%s'
- Unexpected node type -
- @EmbeddedTable only supported for use on entity or mapped-su
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/8dd1321a1a50de24.
Report an issue: GitHub.