hibernate/hibernate-orm · error · MappingException
A '@JoinColumn' references a column named '{}' but the targe
Error message
A '@JoinColumn' references a column named '{}' but the target entity '{}' has no property which maps to this column What it means
A '@JoinColumn(referencedColumnName=...)' names a column on the target entity, but no property of that entity maps the column, so Hibernate cannot resolve the reference. The code deliberately rethrows it as FailedSecondPassException so the metadata collector can retry later passes in case the binding is merely out of order; if the error survives to the end of bootstrap, the reference itself is wrong.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java:342
* Determine if the given {@link AnnotatedJoinColumns} represent a reference to
* the primary key of the given {@link PersistentClass}, or whether they reference
* some other combination of mapped columns.
*/
public ForeignKeyType getReferencedColumnsType(PersistentClass referencedEntity) {
if ( referencedProperty != null ) {
return NON_PRIMARY_KEY_REFERENCE;
}
if ( columns.isEmpty() ) {
return ForeignKeyType.IMPLICIT_PRIMARY_KEY_REFERENCE; //shortcut
}
final var firstColumn = columns.get( 0 );
final var context = getBuildingContext();
final Object columnOwner = findReferencedColumnOwner( referencedEntity, firstColumn, context );
if ( columnOwner == null ) {
try {
throw new MappingException( "A '@JoinColumn' references a column named '"
+ firstColumn.getReferencedColumn() + "' but the target entity '"
+ referencedEntity.getEntityName() + "' has no property which maps to this column" );
}
catch ( MappingException me ) {
// we throw a recoverable exception here in case this
// is merely an ordering issue, so that the SecondPass
// will get reprocessed later
throw new FailedSecondPassException( me.getMessage(), me );
}
}
final var table = table( columnOwner );
// final List<Selectable> keyColumns = referencedEntity.getKey().getSelectables();
final var keyColumns =
table.getPrimaryKey() == null
? referencedEntity.getKey().getSelectables()
: table.getPrimaryKey().getColumns();
boolean explicitColumnReference = false;
for ( var column : columns ) {View on GitHub (pinned to fad1729dce)
Solutions
- Correct referencedColumnName to exactly match the mapped column of a real property on the target entity.
- Add or restore the target property that maps the referenced column (e.g. a @Column(name="...") field or unique @ManyToOne).
- If you do not need a non-PK reference, remove referencedColumnName so the join defaults to the target's primary key.
Example fix
// before @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_email", referencedColumnName = "email_address") // target maps 'email', not 'email_address' private User user; // after @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_email", referencedColumnName = "email") private User user;
Defensive patterns
Strategy: validation
Validate before calling
// Guard: referencedColumnName must match a mapped column on the target entity
Class<?> target = User.class;
Set<String> mapped = new HashSet<>();
for (Field f : target.getDeclaredFields()) {
Column c = f.getAnnotation(Column.class);
if (c != null) mapped.add(c.name().isEmpty() ? f.getName() : c.name());
}
JoinColumn jc = orderField.getAnnotation(JoinColumn.class);
if (jc != null && !jc.referencedColumnName().isEmpty()
&& !mapped.contains(jc.referencedColumnName())) {
throw new IllegalStateException("referencedColumnName '" + jc.referencedColumnName()
+ "' is not mapped by " + target.getSimpleName());
} Try / catch
try {
factory = cfg.buildSessionFactory();
} catch (FailedSecondPassException | AnnotationException e) {
// Hibernate retries ordering internally; if it still fails, the reference is wrong.
// 'has no property which maps to this column' -> fix referencedColumnName
throw newConfigurationException("Unresolvable join column reference", e);
} Prevention
- Default to the target's primary key by omitting referencedColumnName whenever possible.
- Derive referencedColumnName from a constant shared with the target's @Column declaration, never a literal.
- When joining to natural keys, verify the target entity actually maps that column as a field.
When it happens
Trigger: referencedColumnName has a typo or wrong case; the referenced column exists in the database but the target entity has no mapped property for it (no field maps that column); the target attribute is mapped by a @Formula rather than a real column; the FK targets a natural key property that was never mapped.
Common situations: Hand-typed referencedColumnName strings drifted from the schema; joining to a unique business column (SSN, email) that the target entity does not map as a field; databases with case-sensitive identifiers; mappings that worked when the column was the PK but broke after switching to a natural-key reference.
Related errors
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Property '<propertyName>' may not be annotated '@BatchSize'
- One to many association '<propertyName>' was annotated '@Col
- Collection '<propertyName>' was annotated '@Collate'
- Root entity '<entityName>' is annotated '@DiscriminatorOptio
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/2c330b1f52ea9c21.
Report an issue: GitHub.