hibernate/hibernate-orm · error · AnnotationException
Property '${path}' specifies ${columnCount} '@AttributeOverr
Error message
Property '${path}' specifies ${columnCount} '@AttributeOverride's but the overridden property has ${overriddenColumnCount} columns (every column must have exactly one '@AttributeOverride') What it means
When @AttributeOverride is applied to a property, AnnotatedColumn.overrideColumns compares the number of supplied jakarta.persistence.Column entries with the number of columns the overridden property actually maps. A multi-column mapping (composite basic types, embeddables mapping several columns) needs exactly one @Column override per mapped column; any other count throws this AnnotationException. (A code comment notes PersistentClass.validate() often fires first with a vaguer message.)
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java:768
actualColumns,
fractionalSeconds
);
}
}
}
private static jakarta.persistence.Column[] overrideColumns(
jakarta.persistence.Column[] columns,
PropertyHolder propertyHolder,
PropertyData inferredData ) {
final String path = getPath( propertyHolder, inferredData );
final var overriddenCols = propertyHolder.getOverriddenColumn( path );
if ( overriddenCols != null ) {
//check for overridden first
if ( columns != null && overriddenCols.length != columns.length ) {
//TODO: unfortunately, we never actually see this nice error message, since
// PersistentClass.validate() gets called first and produces a worse message
throw new AnnotationException( "Property '" + path
+ "' specifies " + columns.length
+ " '@AttributeOverride's but the overridden property has " + overriddenCols.length
+ " columns (every column must have exactly one '@AttributeOverride')" );
}
if ( BOOT_LOGGER.isTraceEnabled() ) {
BOOT_LOGGER.columnMappingOverridden( inferredData.getPropertyName() );
}
return isEmpty( overriddenCols ) ? null : overriddenCols;
}
else {
return columns;
}
}
private static AnnotatedColumns buildExplicitColumns(
// Comment comment,
PropertyHolder propertyHolder,
PropertyData inferredData,View on GitHub (pinned to fad1729dce)
Solutions
- Count the columns the overridden property maps and supply exactly that many @Column entries in @AttributeOverrides
- If you only meant to rename one column of a composite, still override every column of that composite
- For overriding associations, use @AssociationOverride instead of @AttributeOverride
- If counts look right, check that a different validation error is not masking this one - fix the first mapping error reported
Example fix
// before: two-column property overridden once
@Embeddable
public class Money { // maps amount + currency -> 2 columns
BigDecimal amount;
@Column(length = 3) String currency;
}
@Entity
public class Payment {
@Embedded
@AttributeOverrides({@AttributeOverride(name = "amount", column = @Column(name = "pay_amount"))})
private Money money; // 1 override for 2 columns -> error
}
// after: every column overridden exactly once
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "amount", column = @Column(name = "pay_amount")),
@AttributeOverride(name = "currency", column = @Column(name = "pay_currency"))
})
private Money money; Defensive patterns
Strategy: validation
Validate before calling
// Before boot: known multi-column embeddables need an override per column
// Money maps 2 columns -> require both 'amount' and 'currency' overrides
static boolean overridesComplete(Class<?> entity, Map<String, Integer> columnsByPath) {
for (Field f : entity.getDeclaredFields()) {
AttributeOverrides o = f.getAnnotation(AttributeOverrides.class);
if (o == null) continue;
long distinct = Arrays.stream(o.value())
.map(AttributeOverride::name).distinct().count();
Integer expected = columnsByPath.get(f.getName());
if (expected != null && distinct != expected) 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
- Document the column count of every composite type you use
- When adding a field to an embeddable, update every @AttributeOverrides block that targets it
- Prefer a full, explicit override list over partial renames
When it happens
Trigger: Overriding a property that maps N>1 columns with fewer/more @AttributeOverride entries - e.g. overriding only one column of a two-column user type or of a nested embeddable, or listing overrides for a single-column property twice.
Common situations: Applying @AttributeOverride to embeddables containing multi-column fields (monetary amounts, durations, custom composite types); copying override blocks between embeddables with different column counts; adding a field to an embeddable without adding its override.
Related errors
- '@ColumnDefault' may only be applied to single-column mappin
- '@GeneratedColumn' may only be applied to single-column mapp
- '@Check' may only be applied to single-column mappings but '
- Column mappings for property '${propertyName}' mix nullable
- Column mappings for property '${propertyName}' mix insertabl
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/be2fb14a3ecae608.
Report an issue: GitHub.