hibernate/hibernate-orm · error · AnnotationException
Property '${property}' defines a collection table '${collect
Error message
Property '${property}' defines a collection table '${collectionTable}' in the aggregate component class '${componentClassName}' within an array property, which is not allowed. What it means
The third array-aggregate restriction in AggregateComponentSecondPass.validateComponent: a Collection property inside an in-array component must not define its own collection table (getCollectionTable() != null). Structs live inside the array column, so a join table for a nested collection has no valid home and binding is rejected.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java:213
+ "' 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."
);
}
}
}
}
private boolean isAggregateArray() {
return switch ( component.getAggregateColumn().getSqlTypeCode( context.getMetadataCollector() ) ) {
case SqlTypes.STRUCT_ARRAY,
SqlTypes.STRUCT_TABLE,
SqlTypes.JSON_ARRAY,
SqlTypes.XML_ARRAY,View on GitHub (pinned to fad1729dce)
Solutions
- Move the nested collection out of the embeddable to the owning entity as its own collection
- If the nested data belongs to the struct, store it as a nested aggregate array (struct array inside struct) where supported
- Otherwise drop the field from the aggregate
Example fix
// before: collection table inside an array aggregate
@Embeddable
public class TagGroup {
@ElementCollection
@CollectionTable(name = "tag_group_tags") // rejected within array aggregate
private List<String> tags;
}
@Entity
public class Article {
@Array
private List<TagGroup> tagGroups;
}
// after: collection lifted to the entity
@Entity
public class Article {
@Array
private List<TagGroup> tagGroups; // TagGroup now holds only scalar fields
@ElementCollection
@CollectionTable(name = "article_tags")
private List<String> tags;
} Defensive patterns
Strategy: validation
Validate before calling
// Before boot: embeddables bound for arrays must not declare collection tables
static boolean aggregateHasNoCollectionTables(Class<?> embeddable) {
for (Field f : embeddable.getDeclaredFields()) {
if (f.isAnnotationPresent(ElementCollection.class)
|| f.isAnnotationPresent(OneToMany.class)
|| f.isAnnotationPresent(ManyToMany.class)) {
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
- Model structs as flat value objects: scalars and nested aggregates only
- Collections always belong to entities, never to embeddables stored in arrays
- Add an architecture test (e.g. ArchUnit) forbidding association annotations inside @Embeddable classes used in arrays
When it happens
Trigger: An embeddable used inside an array property contains @ElementCollection with @CollectionTable (or any collection whose table was set), so the second pass sees a collection table inside an in-array component.
Common situations: Adding @ElementCollection fields to an existing struct embeddable; migrating a component model into arrays without pruning nested collections; porting JPA models where embeddables were loosely authored.
Related errors
- Dialect does not support structured array types: ${dialectCl
- Property '${property}' uses one-to-one mapping with mappedBy
- Property '${property}' uses *-to-many mapping with mappedBy
- Database does not support user-defined types (remove '@Struc
- Couldn't find column [${structColumnName}] that was defined
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e8c02b868c587b05.
Report an issue: GitHub.