hibernate/hibernate-orm · error · InstantiationException
Unable to locate constructor for embeddable
Error message
Unable to locate constructor for embeddable
What it means
EmbeddableInstantiatorRecordIndirecting instantiates embeddables modeled as Java records, using the canonical constructor found by the parent EmbeddableInstantiatorRecordStandard. If that constructor lookup failed (constructor == null — the class is not actually a record with a canonical constructor, or it could not be resolved/accessed), instantiate(ValueAccess) throws InstantiationException("Unable to locate constructor for embeddable") for the mapped class before any values are read.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableInstantiatorRecordIndirecting.java:35
protected final int[] index;
public EmbeddableInstantiatorRecordIndirecting(Class<?> javaType, int[] index) {
super( javaType );
this.index = index;
}
public static EmbeddableInstantiatorRecordIndirecting of(Class<?> javaType, String[] propertyNames) {
final var componentNames = getRecordComponentNames( javaType );
final var index = new int[componentNames.length];
return EmbeddableHelper.resolveIndex( propertyNames, componentNames, index )
? new EmbeddableInstantiatorRecordIndirectingWithGap( javaType, index )
: new EmbeddableInstantiatorRecordIndirecting( javaType, index );
}
@Override
public Object instantiate(ValueAccess valuesAccess) {
if ( constructor == null ) {
throw new InstantiationException( "Unable to locate constructor for embeddable", getMappedPojoClass() );
}
try {
final var originalValues = valuesAccess.getValues();
final var values = new Object[originalValues.length];
for ( int i = 0; i < values.length; i++ ) {
values[i] = originalValues[index[i]];
}
return constructor.newInstance( values );
}
catch ( Exception e ) {
throw new InstantiationException( "Could not instantiate entity", getMappedPojoClass(), e );
}
}
// Handles gaps, by leaving the value null for that index
private static class EmbeddableInstantiatorRecordIndirectingWithGap
extends EmbeddableInstantiatorRecordIndirecting {View on GitHub (pinned to fad1729dce)
Solutions
- Confirm the mapped type is a real Java record whose component names match the embeddable's mapped property names.
- If the class is not (or cannot be) a record, stop marking it as one — drop the record representation so a POJO instantiator path is chosen (or fix the integration that sets it).
- For Kotlin, either use Kotlin's support so the right instantiator is selected or provide @EmbeddableInstantiator explicitly.
- If access is the problem (JPMS), open the package containing the record to hibernate.core.
Example fix
// before — plain class processed as record -> constructor lookup fails
public final class Money { // not a record
private final long cents;
public Money(long cents) { this.cents = cents; }
}
// after
public record Money(long cents) { } Defensive patterns
Strategy: type-guard
Validate before calling
// startup guard: classes mapped as record embeddables must really be records
static void checkIsRecord(Class<?> mapped) {
if (!mapped.isRecord())
throw new IllegalStateException("Mapped as record embeddable but not a record: " + mapped.getName());
} Type guard
static boolean usableAsRecordEmbeddable(Class<?> clazz) {
return clazz.isRecord()
&& Arrays.stream(clazz.getRecordComponents()).map(RecordComponent::getName).count() > 0
&& Modifier.isPublic(clazz.getDeclaredConstructors()[0].getModifiers());
} Prevention
- Keep record embeddables as true Java records with component names equal to mapped property names.
- For Kotlin data classes, do not rely on the Java-record instantiator path — provide @EmbeddableInstantiator.
- After refactors that turn records into classes, fix the mapping/instantiator in the same change.
When it happens
Trigger: A mapping marked record=true resolving to a class that is not a java.lang.Class record (e.g., a plain class misreported as record during metadata processing, or a Kotlin class compiled without the record facade), or a record whose canonical constructor is not accessible to Hibernate; then triggering any load or persist path that instantiates the embeddable.
Common situations: Kotlin data classes mistaken for Java records; class replaced by a non-record with the same name after refactoring while the mapping metadata still treats it as record; split packages/multi-release jars where the runtime class differs from the compile-time one; custom integrations forcing isRecord on the Component.
Related errors
- component type [{}] specifies {} properties for the instanti
- could not find property [{}] defined in the @Instantiator wi
- component type [{}] has {} properties but the instantiator o
- Could not instantiate entity
- Cannot instantiate abstract class or interface
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/14eed66f9a496616.
Report an issue: GitHub.