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 loader

View on GitHub (pinned to fad1729dce)

Solutions

  1. Register the transformer only once per persistence unit; remove or guard the duplicate pushClassTransformer call.
  2. Check isClassTransformerRegistrationDisabled() before pushing and skip when a transformer is already in place.
  3. Create a fresh PersistenceUnitInfoDescriptor for a second bootstrap instead of reusing the same instance.
  4. 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

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


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