hibernate/hibernate-orm · error · UnsupportedOperationException

EntityPersister implementation '{className}' does not suppor

Error message

EntityPersister implementation '{className}' does not support 'MultiNaturalIdLoader'

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java:604

	}

	/**
	 * Determine whether this entity defines any lazy properties (when bytecode
	 * instrumentation is enabled).
	 *
	 * @return True if the entity has properties mapped as lazy; false otherwise.
	 */
	boolean hasLazyProperties();

	default NaturalIdLoader<?> getNaturalIdLoader() {
		throw new UnsupportedOperationException(
				"EntityPersister implementation '" + getClass().getName()
						+ "' does not support 'NaturalIdLoader'"
		);
	}

	default MultiNaturalIdLoader<?> getMultiNaturalIdLoader() {
		throw new UnsupportedOperationException(
				"EntityPersister implementation '" + getClass().getName()
						+ "' does not support 'MultiNaturalIdLoader'"
		);
	}

	/**
	 * Load an instance of the persistent class.
	 */
	Object load(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session);

	/**
	 * Load an instance of the persistent class.
	 */
	Object load(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session);

	default Object load(Object id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly)
			throws HibernateException {
		return load( id, optionalObject, lockOptions, session );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Override getMultiNaturalIdLoader() in the custom persister (together with getNaturalIdLoader())
  2. Remove the custom persister for entities needing multi natural-id loading
  3. Loop over single natural-id loads (byNaturalId) or fall back to PK-based multiLoad for that entity

Example fix

// before
List<MyEntity> all = session.byMultipleNaturalId(MyEntity.class).multiLoad(codes); // custom persister

// after
List<MyEntity> all = codes.stream()
        .map(c -> session.bySimpleNaturalId(MyEntity.class).load(c))
        .toList(); // single natural-id path, still requires getNaturalIdLoader support
Defensive patterns

Strategy: validation

Validate before calling

EntityPersister p = sessionFactory.getRuntimeMetamodels()
        .getMappingMetamodel()
        .getEntityDescriptor(Product.class);
if ( p.hasNaturalIdentifier()
        && p instanceof org.hibernate.persister.entity.AbstractEntityPersister ) {
    List<?> all = session.byMultipleNaturalId(Product.class).multiLoad(codes);
}

Type guard

static boolean supportsMultiNaturalIdLoad(EntityPersister persister) {
    return persister.hasNaturalIdentifier()
        && persister instanceof org.hibernate.persister.entity.AbstractEntityPersister;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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