hibernate/hibernate-orm · error · InstantiationException

Unable to locate constructor for embeddable

Error message

Unable to locate constructor for embeddable

What it means

Thrown by EmbeddableInstantiatorRecordStandard.instantiate when the constructor resolved in the class constructor phase is null. The constructor is looked up once via getConstructorOrNull(javaType, getRecordComponentTypes(javaType)); it remains null when the mapped embeddable class does not expose a constructor whose parameter types match the record component types - in practice, when record representation is used for a class that is not a genuine record, or whose canonical constructor cannot be reflectively matched.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableInstantiatorRecordStandard.java:31

import static org.hibernate.internal.util.ReflectHelper.getConstructorOrNull;
import static org.hibernate.internal.util.ReflectHelper.getRecordComponentTypes;

/**
 * Support for instantiating embeddables as record representation
 */
public class EmbeddableInstantiatorRecordStandard extends AbstractPojoInstantiator implements EmbeddableInstantiator {

	protected final Constructor<?> constructor;

	public EmbeddableInstantiatorRecordStandard(Class<?> javaType) {
		super( javaType );
		constructor = getConstructorOrNull( javaType, getRecordComponentTypes( javaType ) );
	}

	@Override
	public Object instantiate(ValueAccess valuesAccess) {
		if ( constructor == null ) {
			throw new InstantiationException( "Unable to locate constructor for embeddable", getMappedPojoClass() );
		}

		try {
			return constructor.newInstance( valuesAccess.getValues() );
		}
		catch ( Exception e ) {
			throw new InstantiationException( "Could not instantiate entity", getMappedPojoClass(), e );
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Confirm the mapped class is a real record and the mapping uses it directly (not a wrapper class with @Representation(RECORD))
  2. If the class must stay a POJO, remove the record representation setting and let Hibernate use POJO instantiation
  3. For CompositeUserType, make returnedClass() return the record class whose canonical constructor matches the mapped property types
  4. Catch InstantiationException during a warm-up read right after SessionFactory creation so mapping problems surface at startup, not in production queries

Example fix

// before - CompositeUserType returns a non-record holder but mapping declares RECORD
public class MoneyType implements CompositeUserType<MoneyHolder> {
    public Class<MoneyHolder> returnedClass() { return MoneyHolder.class; } // plain class
}

// after - return the actual record
type public class MoneyType implements CompositeUserType<Money> {
    public Class<Money> returnedClass() { return Money.class; }  // record
}
public record Money(BigDecimal amount, Currency currency) {}
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast at app start instead of first query
Class<?> embeddable = Money.class;
if ( !embeddable.isRecord() ) {
    throw new IllegalStateException("Embeddable " + embeddable.getName() + " must be a record under RECORD representation");
}
Class<?>[] ctorTypes = Arrays.stream(embeddable.getRecordComponents()).map(RecordComponent::getType).toArray(Class[]::new);
embeddable.getDeclaredConstructor(ctorTypes).setAccessible(true); // throws if unresolvable/inaccessible

Type guard

static boolean hasCanonicalRecordConstructor(Class<?> c) {
    if (!c.isRecord()) return false;
    try {
        Class<?>[] t = Arrays.stream(c.getRecordComponents()).map(RecordComponent::getType).toArray(Class[]::new);
        c.getDeclaredConstructor(t);
        return true;
    } catch (NoSuchMethodException | SecurityException e) { return false; }
}

Try / catch

catch ( org.hibernate.InstantiationException e ) {
    if ( "Unable to locate constructor for embeddable".equals(e.getMessage()) ) {
        throw new MappingError("Embeddable " + e.getMessage() + " has no canonical record constructor - fix the mapping", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Boot succeeds but the first load/query of the embeddable calls instantiate() and hits the null-constructor branch; @Representation(RepresentationMode.RECORD) on a non-record embeddable class; a record type consumed through a custom CompositeUserType whose returnedClass is not the record itself; record loaded through a JavaType descriptor reporting non-matching component types.

Common situations: Hibernate 6 migrations where RepresentationMode.RECORD was introduced to keep old mappings; misconfigured CompositeUserType implementations; annotation processors generating embeddable stubs that are not records.

Related errors


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