hibernate/hibernate-orm · error · AnnotationException
Property '<propertyName>' may not be annotated '@BatchSize'
Error message
Property '<propertyName>' may not be annotated '@BatchSize'
What it means
When @BatchSize sits on a property, BatchSizeBinder accepts only Collection values (lazy collection batch fetching). For any other property shape — @Basic, @ManyToOne, @OneToOne, @Embedded — the value is not a Collection and binding throws an AnnotationException naming the property. To-one batch fetching is configured on the target entity class, not the attribute.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/binder/internal/BatchSizeBinder.java:44
@Override
public void bind(BatchSize batchSize, MetadataBuildingContext context, PersistentClass persistentClass) {
persistentClass.setBatchSize( batchSize.size() );
}
@Override
public void bind(BatchSize batchSize, MetadataBuildingContext context, Component embeddableClass) {
throw new AnnotationException("Class '" + embeddableClass.getComponentClassName()
+ "' is an '@Embeddable' type and may not be annotated '@BatchSize'");
}
@Override
public void bind(BatchSize batchSize, MetadataBuildingContext context, PersistentClass persistentClass, Property property) {
final Value value = property.getValue();
if ( value instanceof Collection collection ) {
collection.setBatchSize( batchSize.size() );
}
else {
throw new AnnotationException("Property '" + property.getName() + "' may not be annotated '@BatchSize'");
}
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- For lazy @ManyToOne/@OneToOne batch fetching, move @BatchSize to the referenced @Entity class.
- For @OneToMany/@ManyToMany/@ElementCollection, keep @BatchSize on the collection property — that is the supported case.
- Otherwise delete the @BatchSize annotation from the property.
Example fix
// before
@Entity
public class Order {
@BatchSize(size = 20)
@ManyToOne(fetch = FetchType.LAZY)
private User user;
}
// after
@Entity
@BatchSize(size = 20) // applies when loading Users
public class User { ... }
@Entity
public class Order {
@ManyToOne(fetch = FetchType.LAZY)
private User user;
} Defensive patterns
Strategy: validation
Validate before calling
for (Field f : cls.getDeclaredFields()) {
if (f.isAnnotationPresent(org.hibernate.annotations.BatchSize.class)
&& !java.util.Collection.class.isAssignableFrom(f.getType())) {
throw new IllegalStateException("@BatchSize only allowed on collection properties: "
+ cls.getName() + "." + f.getName());
}
} Try / catch
Catch org.hibernate.AnnotationException around SessionFactory build; the message names the property. Fail fast — this is a mapping defect, not a runtime condition to recover from.
Prevention
- Entity-level @BatchSize for to-one batch fetching; property-level only on collections.
- Review annotations whenever an association's cardinality changes.
- Add a reflection-based annotation lint to the test suite.
When it happens
Trigger: Annotating a non-collection attribute with @BatchSize, most commonly @ManyToOne(fetch = LAZY) or @OneToOne; at SessionFactory build the attribute binder sees a non-Collection Value and throws.
Common situations: Trying to enable batch fetching for lazy to-one associations by annotating the attribute (the annotation belongs on the referenced entity class); confusing entity-level with collection-level @BatchSize; stale annotation after changing an association's cardinality.
Related errors
- Class '<componentClassName>' is an '@Embeddable' type and ma
- One to many association '<propertyName>' was annotated '@Col
- Collection '<propertyName>' was annotated '@Collate'
- Root entity '<entityName>' is annotated '@DiscriminatorOptio
- Class '<className>' is not the root class of an entity inher
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/9535ded5f2025540.
Report an issue: GitHub.