hibernate/hibernate-orm · error · AnnotationException
Property '${property}' uses *-to-many mapping with mappedBy
Error message
Property '${property}' uses *-to-many mapping with mappedBy '${mappedByProperty}' in the aggregate component class '${componentClassName}' within an array property, which is not allowed. What it means
Same validation pass as the one-to-one case: AggregateComponentSecondPass.validateComponent rejects any Collection-typed property inside an array-bound aggregate that declares mappedBy (getMappedByProperty() != null), i.e. a bidirectional @OneToMany/@ManyToMany. Struct elements stored in arrays cannot be inverse sides of a relationship.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java:203
final Value value = property.getValue();
if ( value instanceof Component comp ) {
validateComponent( comp, qualify( basePath, property.getName() ), inArray );
}
else if ( value instanceof ToOne toOne ) {
if ( inArray && toOne.getReferencedPropertyName() != null ) {
throw new AnnotationException(
"Property '" + qualify( basePath, property.getName() )
+ "' uses one-to-one mapping with mappedBy '"
+ toOne.getReferencedPropertyName()
+ "' in the aggregate component class '"
+ component.getComponentClassName()
+ "' within an array property, which is not allowed."
);
}
}
else if ( value instanceof Collection collection ) {
if ( inArray && collection.getMappedByProperty() != null ) {
throw new AnnotationException(
"Property '" + qualify( basePath, property.getName() )
+ "' uses *-to-many mapping with mappedBy '"
+ collection.getMappedByProperty()
+ "' in the aggregate component class '"
+ component.getComponentClassName()
+ "' within an array property, which is not allowed."
);
}
if ( inArray && collection.getCollectionTable() != null ) {
throw new AnnotationException(
"Property '" + qualify( basePath, property.getName() )
+ "' defines a collection table '"
+ collection.getCollectionTable()
+ "' in the aggregate component class '"
+ component.getComponentClassName()
+ "' within an array property, which is not allowed."
);
}View on GitHub (pinned to fad1729dce)
Solutions
- Move the @OneToMany/@ManyToMany out of the embeddable onto the owning entity
- If the collection is really part of the struct value, model it as a nested aggregate array instead of an association
- Remove mappedBy if the collection must stay (unidirectional join from the struct side is usually still wrong - prefer moving it out)
- Stop using the embeddable inside arrays and map it as a first-level component
Example fix
// before: bidirectional many-side inside an array aggregate
@Embeddable
public class OrderLine {
@OneToMany(mappedBy = "orderLine") // rejected: mappedBy within array aggregate
private List<Attachment> attachments;
}
@Entity
public class Order {
@Array
private List<OrderLine> lines;
}
// after: ownership lives on the entity; the aggregate keeps only value data
@Embeddable
public class OrderLine { /* value fields only */ }
@Entity
public class Attachment {
@ManyToOne @JoinColumn(name = "order_id")
private Order order;
} Defensive patterns
Strategy: validation
Validate before calling
// Before boot: aggregates used in arrays must not contain mappedBy collections
static boolean aggregateHasNoMappedByCollections(Class<?> embeddable) {
for (Field f : embeddable.getDeclaredFields()) {
OneToMany otm = f.getAnnotation(OneToMany.class);
ManyToMany mtm = f.getAnnotation(ManyToMany.class);
if ((otm != null && !otm.mappedBy().isEmpty())
|| (mtm != null && !mtm.mappedBy().isEmpty())) {
return false;
}
}
return true;
} Try / catch
try {
final SessionFactory sf = new MetadataSources(standardServiceRegistry)
.addAnnotatedClass(MyEntity.class)
.buildMetadata()
.buildSessionFactory();
} catch (AnnotationException | MappingException e) {
throw new IllegalStateException("Invalid ORM mapping, aborting startup: " + e.getMessage(), e);
} Prevention
- Never declare associations inside value-type embeddables; keep them on entities
- Review every embeddable before reusing it inside an @Array aggregate
- Validate the full mapping in CI with a SessionFactory build
When it happens
Trigger: An embeddable used inside an @Array or aggregate element-collection contains @OneToMany(mappedBy = ...) or @ManyToMany(mappedBy = ...), triggering the inArray validation during the second pass.
Common situations: Copying working entity patterns (bidirectional collections) into a new struct aggregate; embedding an existing @Embeddable with collection associations into an array column; schema-first designs where the struct was modeled like a mini-entity.
Related errors
- Property '${property}' uses one-to-one mapping with mappedBy
- Dialect does not support structured array types: ${dialectCl
- Property '${property}' defines a collection table '${collect
- Unable to resolve mapped-by path : (%s) %s
- Database does not support user-defined types (remove '@Struc
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/8049a6e2d15debdb.
Report an issue: GitHub.