hibernate/hibernate-orm · error · PersistenceException
Persistence unit [{}] can only have a single class transform
Error message
Persistence unit [{}] can only have a single class transformer. What it means
Thrown by PersistenceUnitInfoDescriptor.pushClassTransformer() as a PersistenceException when a second class transformer registration is attempted for the same persistence unit. Hibernate allows exactly one ClassTransformer per persistence unit because bytecode enhancement is applied once, up front; any subsequent pushClassTransformer call is treated as a configuration error rather than being silently ignored.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceUnitInfoDescriptor.java:143
@Override
public List<String> getMappingFileNames() {
return persistenceUnitInfo.getMappingFileNames();
}
@Override
public List<URL> getJarFileUrls() {
return persistenceUnitInfo.getJarFileUrls();
}
@Override
public boolean isClassTransformerRegistrationDisabled() {
return disableClassTransformerRegistration;
}
@Override
public ClassTransformer pushClassTransformer(EnhancementContext enhancementContext) {
if ( this.classTransformer != null ) {
throw new PersistenceException(
"Persistence unit ["
+ persistenceUnitInfo.getPersistenceUnitName()
+ "] can only have a single class transformer."
);
}
final TransformerKey transformerKey = TransformerKey.from( persistenceUnitInfo );
if ( !TransformerTracker.canSupplyTransformer( transformerKey ) ) {
// transformer was already registered from `jakarta.persistence.spi.PersistenceProvider#getClassTransformer`
// just skip
if ( JPA_LOGGER.isTraceEnabled() ) {
JPA_LOGGER.duplicatedRequestForClassTransformer( transformerKey.puName(), transformerKey.loaderName() );
}
// EARLY EXIT!!!
return null;
}
// During testing, we will return a null temp class loaderView on GitHub (pinned to fad1729dce)
Solutions
- Register the transformer only once per persistence unit; remove or guard the duplicate pushClassTransformer call.
- Check isClassTransformerRegistrationDisabled() before pushing and skip when a transformer is already in place.
- Create a fresh PersistenceUnitInfoDescriptor for a second bootstrap instead of reusing the same instance.
- If a container already registered the transformer, rely on that registration instead of adding your own.
Example fix
// before
transformer1 = descriptor.pushClassTransformer(ctx);
transformer2 = descriptor.pushClassTransformer(ctx); // throws
// after
transformer1 = descriptor.pushClassTransformer(ctx);
if (transformer1 == null) { transformer1 = descriptor.pushClassTransformer(ctx); } // only when none yet Defensive patterns
Strategy: validation
Validate before calling
// push at most one transformer per persistence unit
if (!persistenceUnitInfo.isClassTransformerRegistrationDisabled() && transformerHolder.get() == null) {
transformerHolder.set(descriptor.pushClassTransformer(enhancementContext));
} Prevention
- Centralize transformer registration in one startup component and track the registered instance.
- Reuse the transformer returned by the first push instead of pushing again.
When it happens
Trigger: Calling pushClassTransformer() twice on the same PersistenceUnitInfoDescriptor - typically one call from Hibernate's enhancement support and another from user code or a second integrator/bootstrapper touching the same persistence unit during startup.
Common situations: Two frameworks or integrators both trying to register a ClassTransformer on the same PU (e.g. a custom agent plus container-driven enhancement); re-running bootstrap logic against the same PersistenceUnitInfo without a fresh descriptor; duplicated integration code after refactoring startup.
Related errors
- Association '${path}' targets the type '${type}' which does
- Error performing schema management [persistence unit: {}]
- Unable to build Hibernate SessionFactory [persistence unit:
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Property '<propertyName>' may not be annotated '@BatchSize'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/b7837f7b5c018e97.
Report an issue: GitHub.