{"record":{"id":"14eed66f9a496616","repo":"hibernate/hibernate-orm","slug":"unable-to-locate-constructor-for-embeddable-14eed6","errorCode":null,"errorMessage":"Unable to locate constructor for embeddable","messagePattern":"Unable to locate constructor for embeddable","errorType":"exception","errorClass":"InstantiationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableInstantiatorRecordIndirecting.java","lineNumber":35,"sourceCode":"\tprotected final int[] index;\n\n\tpublic EmbeddableInstantiatorRecordIndirecting(Class<?> javaType, int[] index) {\n\t\tsuper( javaType );\n\t\tthis.index = index;\n\t}\n\n\tpublic static EmbeddableInstantiatorRecordIndirecting of(Class<?> javaType, String[] propertyNames) {\n\t\tfinal var componentNames = getRecordComponentNames( javaType );\n\t\tfinal var index = new int[componentNames.length];\n\t\treturn EmbeddableHelper.resolveIndex( propertyNames, componentNames, index )\n\t\t\t\t? new EmbeddableInstantiatorRecordIndirectingWithGap( javaType, index )\n\t\t\t\t: new EmbeddableInstantiatorRecordIndirecting( javaType, index );\n\t}\n\n\t@Override\n\tpublic Object instantiate(ValueAccess valuesAccess) {\n\t\tif ( constructor == null ) {\n\t\t\tthrow new InstantiationException( \"Unable to locate constructor for embeddable\", getMappedPojoClass() );\n\t\t}\n\n\t\ttry {\n\t\t\tfinal var originalValues = valuesAccess.getValues();\n\t\t\tfinal var values = new Object[originalValues.length];\n\t\t\tfor ( int i = 0; i < values.length; i++ ) {\n\t\t\t\tvalues[i] = originalValues[index[i]];\n\t\t\t}\n\t\t\treturn constructor.newInstance( values );\n\t\t}\n\t\tcatch ( Exception e ) {\n\t\t\tthrow new InstantiationException( \"Could not instantiate entity\", getMappedPojoClass(), e );\n\t\t}\n\t}\n\n\t// Handles gaps, by leaving the value null for that index\n\tprivate static class EmbeddableInstantiatorRecordIndirectingWithGap\n\t\t\textends EmbeddableInstantiatorRecordIndirecting {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/metamodel/internal/EmbeddableInstantiatorRecordIndirecting.java#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — plain class processed as record -> constructor lookup fails\npublic final class Money { // not a record\n    private final long cents;\n    public Money(long cents) { this.cents = cents; }\n}\n\n// after\npublic record Money(long cents) { }","handlingStrategy":"type-guard","validationCode":"// startup guard: classes mapped as record embeddables must really be records\nstatic void checkIsRecord(Class<?> mapped) {\n    if (!mapped.isRecord())\n        throw new IllegalStateException(\"Mapped as record embeddable but not a record: \" + mapped.getName());\n}","typeGuard":"static boolean usableAsRecordEmbeddable(Class<?> clazz) {\n    return clazz.isRecord()\n            && Arrays.stream(clazz.getRecordComponents()).map(RecordComponent::getName).count() > 0\n            && Modifier.isPublic(clazz.getDeclaredConstructors()[0].getModifiers());\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["hibernate","embeddable","java-records","instantiation","constructor"],"backgroundTag":"record-mapping-error","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}