hibernate/hibernate-orm · error · MappingException

Struct [%s] is defined by multiple components %s with differ

Error message

Struct [%s] is defined by multiple components %s with different number of mappings %d and %d

What it means

When multiple components map to the same database struct name, Hibernate enforces that they describe the identical type. validateEqual first compares column counts; if two definitions of the same struct map different numbers of columns, this MappingException reports the struct name, the involved component classes, and both counts.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java:394

	}

	private static void ensureParentInitialized(
			InFlightMetadataCollector metadataCollector,
			AggregateColumn aggregateColumn) {
		do {
			// Trigger resolving of the value so that the column gets properly filled
			aggregateColumn.getValue().getType();
			// Make sure this state is initialized
			aggregateColumn.getSqlTypeCode( metadataCollector );
			aggregateColumn.getSqlType( metadataCollector );
			aggregateColumn = aggregateColumn.getComponent().getParentAggregateColumn();
		} while ( aggregateColumn != null );
	}

	private void validateEqual(UserDefinedObjectType udt1, UserDefinedObjectType udt2) {
		if ( udt1.getColumnSpan() != udt2.getColumnSpan() ) {
			throw new MappingException(
					String.format(
							"Struct [%s] is defined by multiple components %s with different number of mappings %d and %d",
							udt1.getName(),
							findComponentClasses(),
							udt1.getColumnSpan(),
							udt2.getColumnSpan()

					)
			);
		}
		final List<Column> missingColumns = new ArrayList<>();
		for ( Column column1 : udt1.getColumns() ) {
			final Column column2 = udt2.getColumn( column1 );
			if ( column2 == null ) {
				missingColumns.add( column1 );
			}
			else if ( !column1.getSqlType().equals( column2.getSqlType() ) ) {
				throw new MappingException(

View on GitHub (pinned to fad1729dce)

Solutions

  1. Make the column sets identical across all components sharing the struct name
  2. If the types genuinely differ, give one of them a different struct name
  3. Delete the stale/duplicate embeddable mapping
  4. After fixing, ensure only one canonical Java class represents each database UDT

Example fix

// before: same struct name, different column counts
@Embeddable @Struct(name = "address")
public class AddressV1 { String street; String city; }              // 2 columns

@Embeddable @Struct(name = "address")
public class AddressV2 { String street; String city; String zip; }  // 3 columns -> error

// after: one canonical definition (or distinct struct names)
@Embeddable @Struct(name = "address")
public class Address { String street; String city; String zip; }   // single source of truth
Defensive patterns

Strategy: validation

Validate before calling

// Before boot: embeddables sharing a struct name must map the same number of columns
static Map<String, List<Class<?>>> structFieldCounts(List<Class<?>> embeddables) {
    Map<String, List<Class<?>>> byStruct = new HashMap<>();
    for (Class<?> c : embeddables) {
        Struct s = c.getAnnotation(Struct.class);
        if (s != null) byStruct.computeIfAbsent(s.name(), k -> new ArrayList<>()).add(c);
    }
    return byStruct; // assert each list's members all map equal column counts
}

Try / catch

try {
    sessionFactory = metadata.buildSessionFactory();
} catch (MappingException e) {
    if (e.getMessage().contains("different number of mappings")) {
        throw new IllegalStateException("Two embeddables share a struct name but map different columns", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Two (or more) embeddable classes, or two mappings of embeddables, carry the same @Struct(name = ...) but declare different numbers of persistent attributes/columns - e.g. one Address struct with 3 fields and another with 4.

Common situations: Copy-pasting an embeddable and adding a field to only one copy; different teams mapping the same database UDT with diverging Java models; a stale duplicate embeddable left behind after refactoring.

Related errors


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