hibernate/hibernate-orm · error · CompositeValueGenerationException
Mismatch between number of collected generated column values
Error message
Mismatch between number of collected generated column values and number of columns for composite attribute: {}.{} What it means
Thrown while Hibernate builds the on-execution value-generation plan for a composite (embeddable) attribute. When a sub-property's generator references its generated values in the SQL (referenceColumnsInSql()=true and the values are not written as parameters), the generator must supply exactly one SQL fragment per column of that sub-property via getReferencedColumnValues(dialect, eventType). This CompositeValueGenerationException reports that the returned array length differs from the sub-property's column span.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/generator/internal/CompositeGeneratorBuilder.java:140
if ( details != null ) {
if ( generatorEventTypes.contains( eventType ) ) {
if ( !onExecutionGenerator.referenceColumnsInSql( dialect, eventType ) ) {
details.excludeColumns( columnIndex, span );
}
else if ( onExecutionGenerator.writePropertyValue( eventType ) ) {
// leave the default parameter marker values in place
}
else {
final String[] referencedColumnValues =
onExecutionGenerator.getReferencedColumnValues( dialect, eventType );
if ( referencedColumnValues == null ) {
throw new CompositeValueGenerationException(
"Generated column values were not provided for composite attribute: "
+ mappingProperty.getName() + '.' + property.getName()
);
}
if ( referencedColumnValues.length != span ) {
throw new CompositeValueGenerationException(
"Mismatch between number of collected generated column values and number of columns for composite attribute: "
+ mappingProperty.getName() + '.' + property.getName()
);
}
details.setColumnValues( columnIndex, referencedColumnValues );
}
}
else if ( !onExecutionGenerator.allowMutation() ) {
details.excludeColumns( columnIndex, span );
}
}
}
}
columnIndex += span;
}
for ( var details : columnValueDetailsByEvent.values() ) {
details.finalizeDetails();View on GitHub (pinned to fad1729dce)
Solutions
- If you wrote the OnExecutionGenerator, make getReferencedColumnValues(dialect, eventType) return exactly one entry per column occupied by the sub-property (derive the count from the property's column span, not a constant)
- Restrict on-execution generation to single-column members of the embeddable; move the generated value to a basic attribute on the entity
- For multi-column members, switch to in-memory generation (@Generated(event=...) or a BeforeExecutionGenerator) that writes all columns as parameters
- If only built-in annotations are involved, double-check @Columns / composite UserType mappings on the offending member (the message names Entity.embeddable.member)
- If the mapping looks valid, report a Hibernate bug with the entity, embeddable, and generator class
Example fix
// before — member spans 2 columns but the generator supplies 1 referenced value
@Embeddable
public class Availability {
@GeneratedColumn(event = EventType.INSERT) // on-execution generation
@Columns({@Column(name = "opens_at"), @Column(name = "closes_at")})
MyLocalTimeRange window; // CompositeUserType over 2 columns
}
// after — on-execution generation only on a single-column member
@Embeddable
public class Availability {
@GeneratedColumn(event = EventType.INSERT)
@Column(name = "opens_at")
Instant opensAt;
@Column(name = "closes_at")
Instant closesAt;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
sessionFactory = new MetadataSources(serviceRegistry)
.addAnnotatedClass(Order.class)
.buildMetadata()
.buildSessionFactory();
}
catch (CompositeValueGenerationException e) {
// message names the offending path: "<entity>.<embeddable>.<member>"
throw new IllegalStateException("Invalid generated-value mapping: " + e.getMessage(), e);
} Prevention
- Keep @GeneratedColumn and on-execution generators on single-column basic attributes, not multi-column members of embeddables
- Size getReferencedColumnValues(...) from the mapped column span, never a hard-coded array
- Boot the SessionFactory in a CI smoke test so mapping errors fail the build instead of production
When it happens
Trigger: Building a SessionFactory where an @Embeddable (or embedded id) member has an on-execution generator — e.g. @GeneratedColumn, identity columns, or a custom OnExecutionGenerator — whose getReferencedColumnValues(dialect, eventType) returns a String[] whose length != that member's column span. Example: a member mapped over 2 columns (@Columns or a CompositeUserType) whose generator returns one value, or a custom generator returning a hard-coded array.
Common situations: Applying @GeneratedColumn or trigger-based on-execution generation to multi-column members of embeddables; custom OnExecutionGenerator implementations that hard-code referenced column values; switching a member from a single column to a multi-column type (duration/range/period CompositeUserTypes) without updating the generator; Hibernate upgrades that tightened the composite generation contract.
Related errors
- Property '${path}' specifies ${columnCount} '@AttributeOverr
- '@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 '
- CurrentTimestampGeneration requires exactly one column
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/d954d11bbf99fc91.
Report an issue: GitHub.