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

  1. 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)
  2. Restrict on-execution generation to single-column members of the embeddable; move the generated value to a basic attribute on the entity
  3. For multi-column members, switch to in-memory generation (@Generated(event=...) or a BeforeExecutionGenerator) that writes all columns as parameters
  4. If only built-in annotations are involved, double-check @Columns / composite UserType mappings on the offending member (the message names Entity.embeddable.member)
  5. 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

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


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/d954d11bbf99fc91. Report an issue: GitHub.