hibernate/hibernate-orm · error · MappingException

Struct [%s] of class [%s] is defined by multiple components

Error message

Struct [%s] of class [%s] is defined by multiple components with different mappings [%s] and [%s] for column [%s]

What it means

The second stage of validateEqual for struct definitions sharing one name: matching columns must also agree on SQL type. If column X maps to varchar(255) in one component and to a Clob/varchar(10)/different type in the other, Hibernate throws this MappingException showing the struct name, component class, both SQL types, and the column.

Source

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

			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(
						String.format(
								"Struct [%s] of class [%s] is defined by multiple components with different mappings [%s] and [%s] for column [%s]",
								udt1.getName(),
								componentClassDetails.getName(),
								column1.getSqlType(),
								column2.getSqlType(),
								column1.getCanonicalName()
						)
				);
			}
		}

		if ( !missingColumns.isEmpty() ) {
			throw new MappingException(
					String.format(
							"Struct [%s] is defined by multiple components %s but some columns are missing in [%s]: %s",
							udt1.getName(),
							findComponentClasses(),

View on GitHub (pinned to fad1729dce)

Solutions

  1. Align the type mapping of the differing column in both components (same JDBC type, length, Lob usage)
  2. Preferably collapse both components into one canonical embeddable class
  3. If the databases/UDTs truly differ, rename one struct so the definitions stop colliding

Example fix

// before: same struct, same field, different SQL type
@Embeddable @Struct(name = "note")
public class NoteA { @Column(length = 100) String text; }

@Embeddable @Struct(name = "note")
public class NoteB { @Lob String text; }        // CLOB vs varchar -> error

// after: identical mapping
@Embeddable @Struct(name = "note")
public class NoteA { @Column(length = 100) String text; }

@Embeddable @Struct(name = "note")
public class NoteB { @Column(length = 100) String text; }
Defensive patterns

Strategy: validation

Validate before calling

// Before boot: embeddables sharing a struct name must agree on every column's SQL shape
static boolean structColumnTypesAgree(Class<?> a, Class<?> b) {
    Map<String, Column> colsB = columnMap(b);
    for (Map.Entry<String, Column> e : columnMap(a).entrySet()) {
        Column other = colsB.get(e.getKey());
        if (other == null) return false;
        if (e.getValue().length() != other.length()
                || e.getValue().lob() != other.lob()) return false;
    }
    return colsB.keySet().equals(columnMap(a).keySet());
}

Try / catch

try {
    sessionFactory = metadata.buildSessionFactory();
} catch (MappingException e) {
    if (e.getMessage().contains("different mappings")) {
        throw new IllegalStateException("Diverging column types between components of one struct", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Two embeddables with the same @Struct(name=...) declare the same field names but with different mapped types or column definitions - e.g. String vs @Lob String, different lengths, an enum mapped STRING vs ORDINAL, or different @JdbcTypeCode.

Common situations: Two teams mapping the same UDT independently; refactoring one embeddable's types without updating its twin; copy-paste divergence where a length or Lob annotation was added on one side only.

Related errors


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