hibernate/hibernate-orm · error · AnnotationException

Attribute '%s.%s' of type '%s' is annotated '@Bag' (bags are

Error message

Attribute '%s.%s' of type '%s' is annotated '@Bag' (bags are of type '%s' or '%s')

What it means

With @Bag present, the declared Java type of the attribute must be java.util.List or java.util.Collection; those are the only types with bag semantics. CollectionBinder throws this AnnotationException for any other declared raw type (for example java.util.Set), listing the required types in the message.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java:947

		if ( property.hasAnnotationUsage( OrderColumn.class, modelsContext ) ) {
			throw new AnnotationException( "Attribute '"
					+ qualify( property.getDeclaringType().getName(), property.getName() )
					+ "' is annotated '@Bag' and may not also be annotated '@OrderColumn'" );
		}

		if ( property.hasAnnotationUsage( ListIndexBase.class, modelsContext ) ) {
			throw new AnnotationException( "Attribute '"
					+ qualify( property.getDeclaringType().getName(), property.getName() )
					+ "' is annotated '@Bag' and may not also be annotated '@ListIndexBase'" );
		}

		final var collectionJavaType = property.getType().determineRawClass().toJavaClass();
		if ( java.util.List.class.equals( collectionJavaType )
				|| java.util.Collection.class.equals( collectionJavaType ) ) {
			return CollectionClassification.BAG;
		}
		else {
			throw new AnnotationException(
					String.format(
							Locale.ROOT,
							"Attribute '%s.%s' of type '%s' is annotated '@Bag' (bags are of type '%s' or '%s')",
							property.getDeclaringType().getName(),
							property.getName(),
							collectionJavaType.getName(),
							java.util.List.class.getName(),
							java.util.Collection.class.getName()
					)
			);
		}
	}

	private static CollectionClassification determineCollectionClassification(
			Class<?> semanticJavaType,
			MemberDetails property,
			MetadataBuildingContext buildingContext) {
		if ( semanticJavaType.isArray() ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Change the field type to List (or Collection) if bag semantics is intended
  2. Or remove @Bag and keep Set semantics
  3. Do not use custom collection classes with @Bag - only the two JDK interfaces are accepted

Example fix

// before
@Bag
Set<String> tags;   // error: bags are List or Collection

// after
@Bag
List<String> tags;  // or remove @Bag to keep Set semantics
Defensive patterns

Strategy: validation

Validate before calling

// @Bag requires List or Collection declared type
static void checkBagFieldType(Class<?>... entities) {
    for ( Class<?> c : entities ) {
        for ( Field f : c.getDeclaredFields() ) {
            if ( f.isAnnotationPresent( Bag.class ) ) {
                Class<?> t = f.getType();
                if ( !List.class.equals( t ) && !Collection.class.equals( t ) ) {
                    throw new IllegalStateException( "@Bag on non-List/Collection field "
                        + c.getName() + "." + f.getName() );
                }
            }
        }
    }
}

Prevention

When it happens

Trigger: A property has @Bag, its raw Java class is resolved via property.getType().determineRawClass().toJavaClass(), and that class is neither java.util.List nor java.util.Collection.

Common situations: Adding @Bag to a Set-typed attribute while hunting performance issues; switching a collection from List to Set (e.g. to deduplicate) without removing @Bag; custom collection implementations not extending List/Collection.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/7de97b3d083616e0. Report an issue: GitHub.