hibernate/hibernate-orm · error · AnnotationException
Association '{}' is 'mappedBy' another entity and may not sp
Error message
Association '{}' is 'mappedBy' another entity and may not specify the '@JoinColumn' What it means
The mappedBy side of an association is the unowned side: it mirrors the join defined by the owning side and cannot declare its own join mapping. detectMappedByProblem throws this AnnotationException when a mappedBy collection property also carries a direct @JoinColumn or @JoinColumns annotation.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java:1191
includeInOptimisticLockChecks = !isMappedBy;
}
collection.setOptimisticLocked( includeInOptimisticLockChecks );
}
private void bindCache() {
//set cache
if ( isNotBlank( cacheConcurrencyStrategy ) ) {
collection.setCacheConcurrencyStrategy( cacheConcurrencyStrategy );
collection.setCacheRegionName( cacheRegionName );
}
collection.setQueryCacheLayout( queryCacheLayout );
}
private void detectMappedByProblem(boolean isMappedBy) {
if ( isMappedBy ) {
if ( property.hasDirectAnnotationUsage( JoinColumn.class )
|| property.hasDirectAnnotationUsage( JoinColumns.class ) ) {
throw new AnnotationException( "Association '"
+ qualify( propertyHolder.getPath(), propertyName )
+ "' is 'mappedBy' another entity and may not specify the '@JoinColumn'" );
}
if ( propertyHolder.getJoinTable( property ) != null ) {
throw new AnnotationException( "Association '"
+ qualify( propertyHolder.getPath(), propertyName )
+ "' is 'mappedBy' another entity and may not specify the '@JoinTable'" );
}
if ( oneToMany ) {
if ( property.hasDirectAnnotationUsage( MapKeyColumn.class ) ) {
BOOT_LOGGER.mappedByShouldNotSpecifyMapKeyColumn(
qualify( propertyHolder.getPath(), propertyName )
);
}
if ( property.hasDirectAnnotationUsage( OrderColumn.class ) ) {
BOOT_LOGGER.mappedByShouldNotSpecifyOrderColumn(
qualify( propertyHolder.getPath(), propertyName )
);View on GitHub (pinned to fad1729dce)
Solutions
- Remove @JoinColumn/@JoinColumns from the mappedBy side
- Define the join column once on the owning side (the side without mappedBy)
- If this side must own the join, remove mappedBy and give this side @JoinColumn(s) - then clean the other side to mappedBy
Example fix
// before
@Entity
class Comment {
@ManyToOne
@JoinColumn(name = "post_id")
Post post;
}
@Entity
class Post {
@OneToMany(mappedBy = "post")
@JoinColumn(name = "post_id") // error: mappedBy side may not declare join columns
List<Comment> comments;
}
// after
@Entity
class Post {
@OneToMany(mappedBy = "post") // join defined solely by Comment.post
List<Comment> comments;
} Defensive patterns
Strategy: validation
Validate before calling
// Reject @JoinColumn on the mappedBy side before boot
static void checkMappedByJoinColumns(Class<?>... entities) {
for ( Class<?> c : entities ) {
for ( Field f : c.getDeclaredFields() ) {
String mappedBy = null;
OneToMany otm = f.getAnnotation( OneToMany.class );
ManyToMany mtm = f.getAnnotation( ManyToMany.class );
if ( otm != null ) mappedBy = otm.mappedBy();
if ( mtm != null ) mappedBy = mtm.mappedBy();
boolean join = f.isAnnotationPresent( JoinColumn.class )
|| f.isAnnotationPresent( JoinColumns.class );
if ( mappedBy != null && !mappedBy.isBlank() && join ) {
throw new IllegalStateException( "mappedBy side declares @JoinColumn: "
+ c.getName() + "." + f.getName() );
}
}
}
} Prevention
- Rule of thumb: a mappedBy side carries no join metadata of any kind (@JoinColumn, @JoinTable, @OrderBy-index columns)
- Define the FK once on the owning side and let the inverse side mirror it via mappedBy
- Add the mappedBy/@JoinColumn reflection scan to the mapping test suite
When it happens
Trigger: isMappedBy is true for the property and property.hasDirectAnnotationUsage(JoinColumn.class) or JoinColumns.class returns true during detectMappedByProblem; the parallel check for @JoinTable produces a sibling error.
Common situations: Specifying a FK column name on both sides of a bidirectional relation 'for symmetry'; migrating a unidirectional relation to bidirectional without removing the join column from what becomes the inverse side; generator output that always emits @JoinColumn.
Related errors
- Collection '{}' is the unowned side of a bidirectional '@Man
- Association '%s' of entity '%s' is 'mappedBy' a different en
- A '@JoinColumn' references a column named '{}' but the targe
- Error processing @TypeBinderType annotation '%s' for embedda
- Error processing @TypeBinderType annotation '%s' for entity
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/66449b6057d0512c.
Report an issue: GitHub.