hibernate/hibernate-orm · critical · ServiceException
A bean manager was provided via 'jakarta.persistence.bean.ma
Error message
A bean manager was provided via 'jakarta.persistence.bean.manager' but CDI is not available on the Hibernate class loader
What it means
When a BeanManager reference is supplied via 'jakarta.persistence.bean.manager', Hibernate first verifies that the CDI API itself is loadable through its own ClassLoaderService (isCdiAvailable). If jakarta.enterprise.inject.spi.BeanManager cannot be loaded from Hibernate's class loader, it refuses to use the reference and throws ServiceException at bootstrap.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java:80
private static BeanContainer interpretImplicitBeanContainer(ServiceRegistry serviceRegistry) {
final Collection<BeanContainer> beanContainers =
serviceRegistry.requireService( ClassLoaderService.class )
.loadJavaServices( BeanContainer.class );
return switch ( beanContainers.size() ) {
case 1 -> beanContainers.iterator().next();
case 0 -> interpretImplicitCdiBeanContainer( serviceRegistry );
default -> throw new ServiceException( "Multiple BeanContainer service implementations found"
+ " (set '" + BEAN_CONTAINER + "' explicitly)" );
};
}
// simplified CDI support
private static BeanContainer interpretImplicitCdiBeanContainer(ServiceRegistry serviceRegistry) {
final Object beanManager = getConfiguredBeanManager( serviceRegistry );
final boolean isCdiAvailable = isCdiAvailable( serviceRegistry );
if ( beanManager != null ) {
if ( !isCdiAvailable ) {
throw new ServiceException( "A bean manager was provided via '" + JAKARTA_CDI_BEAN_MANAGER
+ "' but CDI is not available on the Hibernate class loader");
}
return CdiBeanContainerBuilder.fromBeanManagerReference( beanManager, serviceRegistry );
}
else {
if ( isCdiAvailable ) {
BEANS_MSG_LOGGER.noBeanManagerButCdiAvailable();
}
return null;
}
}
private static Object getConfiguredBeanManager(ServiceRegistry serviceRegistry) {
final Map<String, Object> settings = serviceRegistry.requireService( ConfigurationService.class ).getSettings();
final Object beanManager = settings.get( JAKARTA_CDI_BEAN_MANAGER );
return beanManager != null ? beanManager : settings.get( CDI_BEAN_MANAGER );
}
View on GitHub (pinned to fad1729dce)
Solutions
- Add jakarta.enterprise:jakarta.enterprise.cdi-api (and an implementation if beans are used) to the same classpath/classloader as hibernate-core.
- In modular setups, ensure Hibernate's module reads the CDI API module (requires static jakarta.enterprise.cdi).
- Remove the 'jakarta.persistence.bean.manager' property when CDI is not actually in use.
- Verify with Class.forName("jakarta.enterprise.inject.spi.BeanManager") on Hibernate's classloader during a startup check.
Example fix
// before
Map<String, Object> props = Map.of("jakarta.persistence.bean.manager", weldBeanManager);
// hibernate-core cannot load jakarta.enterprise.inject.spi.BeanManager -> ServiceException
// after - put the CDI API next to hibernate-core (Maven)
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
</dependency>
// or drop the property entirely when CDI is not used Defensive patterns
Strategy: validation
Validate before calling
// only pass a bean manager if Hibernate can see the CDI API on its classloader
try {
Class.forName("jakarta.enterprise.inject.spi.BeanManager", false,
org.hibernate.Internal.class.getClassLoader());
} catch (ClassNotFoundException e) {
props.remove("jakarta.persistence.bean.manager"); // or fix the classpath first
} Try / catch
try {
emf = Persistence.createEntityManagerFactory("pu", props);
} catch (org.hibernate.service.spi.ServiceException e) {
if (e.getMessage().contains("CDI is not available")) {
// add cdi-api next to hibernate-core, or remove the bean.manager property
throw new ConfigurationException(e.getMessage(), e);
}
throw e;
} Prevention
- Ship jakarta.enterprise.cdi-api on the same classloader as hibernate-core.
- In JPMS deployments, make Hibernate's module read the CDI module.
- Do not set jakarta.persistence.bean.manager unless CDI is really in use.
When it happens
Trigger: Passing a BeanManager while hibernate-core cannot see the CDI API: cdi-api missing from the application classpath, a module-path/layered classloading setup where Hibernate's class loader does not read the CDI module, or the bean manager object coming from a different classloader than Hibernate.
Common situations: Shaded/modular applications that omit jakarta.enterprise.cdi-api; app-server deployments with visibility restrictions on Hibernate's class loader; SE apps where the property is set globally but CDI is not actually used.
Related errors
- Multiple BeanContainer service implementations found (set 'h
- Unable to locate schema [{}] via classpath
- ExtendedBeanManager.LifecycleListener callback not yet calle
- Multiple SchemaManagementTool service registrations found vi
- Unloadable Java type: " + typeName
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c2a183e454787e0e.
Report an issue: GitHub.