{"record":{"id":"84732ba958a0622e","repo":"hibernate/hibernate-orm","slug":"entitypersister-implementation-classname-does-84732b","errorCode":null,"errorMessage":"EntityPersister implementation '{className}' does not support 'MultiNaturalIdLoader'","messagePattern":"EntityPersister implementation '(.+?)' does not support 'MultiNaturalIdLoader'","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java","lineNumber":604,"sourceCode":"\t}\n\n\t/**\n\t * Determine whether this entity defines any lazy properties (when bytecode\n\t * instrumentation is enabled).\n\t *\n\t * @return True if the entity has properties mapped as lazy; false otherwise.\n\t */\n\tboolean hasLazyProperties();\n\n\tdefault NaturalIdLoader<?> getNaturalIdLoader() {\n\t\tthrow new UnsupportedOperationException(\n\t\t\t\t\"EntityPersister implementation '\" + getClass().getName()\n\t\t\t\t\t\t+ \"' does not support 'NaturalIdLoader'\"\n\t\t);\n\t}\n\n\tdefault MultiNaturalIdLoader<?> getMultiNaturalIdLoader() {\n\t\tthrow new UnsupportedOperationException(\n\t\t\t\t\"EntityPersister implementation '\" + getClass().getName()\n\t\t\t\t\t\t+ \"' does not support 'MultiNaturalIdLoader'\"\n\t\t);\n\t}\n\n\t/**\n\t * Load an instance of the persistent class.\n\t */\n\tObject load(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session);\n\n\t/**\n\t * Load an instance of the persistent class.\n\t */\n\tObject load(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session);\n\n\tdefault Object load(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly)\n\t\t\tthrows HibernateException {\n\t\treturn load( id, optionalObject, lockOptions, session );","sourceCodeStart":586,"sourceCodeEnd":622,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java#L586-L622","documentation":"EntityPersister.getMultiNaturalIdLoader() backs batch natural-id loading (session.byMultipleNaturalId(...)). Like getNaturalIdLoader(), only real persisters derived from AbstractEntityPersister implement it; the interface default throws UnsupportedOperationException('EntityPersister implementation ... does not support MultiNaturalIdLoader'), so custom persisters missing the override fail on multi natural-id load calls.","triggerScenarios":"session.byMultipleNaturalId(MyEntity.class).multiLoad(values) (or any code calling persister.getMultiNaturalIdLoader()) on an entity handled by a custom EntityPersister that does not override the method.","commonSituations":"Custom persisters registered for tenancy/auditing; wrapper persisters; test stubs; migrating an application to the multi-load natural-id API while custom persisters are in place.","solutions":["Override getMultiNaturalIdLoader() in the custom persister (together with getNaturalIdLoader())","Remove the custom persister for entities needing multi natural-id loading","Loop over single natural-id loads (byNaturalId) or fall back to PK-based multiLoad for that entity"],"exampleFix":"// before\nList<MyEntity> all = session.byMultipleNaturalId(MyEntity.class).multiLoad(codes); // custom persister\n\n// after\nList<MyEntity> all = codes.stream()\n        .map(c -> session.bySimpleNaturalId(MyEntity.class).load(c))\n        .toList(); // single natural-id path, still requires getNaturalIdLoader support","handlingStrategy":"validation","validationCode":"EntityPersister p = sessionFactory.getRuntimeMetamodels()\n        .getMappingMetamodel()\n        .getEntityDescriptor(Product.class);\nif ( p.hasNaturalIdentifier()\n        && p instanceof org.hibernate.persister.entity.AbstractEntityPersister ) {\n    List<?> all = session.byMultipleNaturalId(Product.class).multiLoad(codes);\n}","typeGuard":"static boolean supportsMultiNaturalIdLoad(EntityPersister persister) {\n    return persister.hasNaturalIdentifier()\n        && persister instanceof org.hibernate.persister.entity.AbstractEntityPersister;\n}","tryCatchPattern":null,"preventionTips":["Test multi natural-id loading once per entity class in CI, especially with custom persisters","Keep natural-id access centralized in repository methods so guards live in one place","Document which entities support natural-id APIs in the project's data-access guidelines"],"tags":["hibernate","orm","natural-id","persister","batch-loading","api-unsupported"],"backgroundTag":"natural-id-not-supported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}