hibernate/hibernate-orm · error · PersistenceException
Hibernate cannot unwrap EntityManagerFactory as '{type.getNa
Error message
Hibernate cannot unwrap EntityManagerFactory as '{type.getName()}' What it means
JPA's EntityManagerFactory.unwrap(Class) must succeed for implementor classes and the JPA interfaces, and throw PersistenceException otherwise. Hibernate supports unwrapping to SessionFactory/SessionFactoryImplementor, EntityManagerFactory, the JpaMetamodel/MappingMetamodel, and the QueryEngine; anything else (e.g. javax.persistence.EntityManagerFactory variants of another provider, DataSource, custom classes) reaches the terminal PersistenceException.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java:1265
}
if ( type.isInstance( runtimeMetamodels ) ) {
return type.cast( runtimeMetamodels );
}
if ( type.isInstance( runtimeMetamodels.getJpaMetamodel() ) ) {
return type.cast( runtimeMetamodels.getJpaMetamodel() );
}
if ( type.isInstance( runtimeMetamodels.getMappingMetamodel() ) ) {
return type.cast( runtimeMetamodels.getMappingMetamodel() );
}
if ( type.isInstance( queryEngine ) ) {
return type.cast( queryEngine );
}
throw new PersistenceException( "Hibernate cannot unwrap EntityManagerFactory as '" + type.getName() + "'" );
}
@Override
public void runInTransaction(@Nonnull Consumer<EntityManager> work) {
inTransaction( work );
}
@Override
public <H extends EntityHandler> void runInTransaction(
@Nonnull Class<H> handlerType, @Nonnull Consumer<H> consumer) {
if ( EntityManager.class.isAssignableFrom( handlerType ) ) {
//noinspection unchecked
inTransaction( (Consumer<EntityManager>) consumer );
}
else if ( EntityAgent.class.isAssignableFrom( handlerType ) ) {
//noinspection unchecked
inStatelessTransaction( (Consumer<EntityAgent>) consumer );
}View on GitHub (pinned to fad1729dce)
Solutions
- Unwrap the EntityManager (not the factory) to get Session/SessionImplementor: em.unwrap(Session.class)
- Use only documented targets on the factory: SessionFactory.class, SessionFactoryImplementor.class, Metamodel/JpaMetamodel, MappingMetamodel, QueryEngine, EntityManagerFactory.class
- To reach the DataSource, unwrap the ServiceRegistry instead: sf.getServiceRegistry().requireService(ConnectionProvider.class)
- After jakarta migration, make sure you pass the jakarta.persistence classes, not javax.persistence leftovers
Example fix
// before Session session = emf.unwrap(Session.class); // PersistenceException: cannot unwrap // after Session session = entityManager.unwrap(Session.class); // or, for factory-level needs: SessionFactoryImplementor sfi = emf.unwrap(SessionFactoryImplementor.class);
Defensive patterns
Strategy: type-guard
Validate before calling
static final Set<Class<?>> FACTORY_UNWRAP_TARGETS = Set.of(
EntityManagerFactory.class, SessionFactory.class,
SessionFactoryImplementor.class, Metamodel.class);
if (FACTORY_UNWRAP_TARGETS.contains(type)) {
return emf.unwrap(type);
} Type guard
static boolean factoryUnwrappable(Class<?> t) {
return EntityManagerFactory.class.equals(t)
|| SessionFactory.class.equals(t)
|| SessionFactoryImplementor.class.equals(t)
|| Metamodel.class.isAssignableFrom(t)
|| t.getName().startsWith("org.hibernate.engine.query.spi.QueryEngine");
} Try / catch
try {
SessionFactory sf = emf.unwrap(SessionFactory.class);
} catch (PersistenceException e) {
// type not supported by Hibernate's factory unwrap — use a dedicated accessor instead
throw new UnsupportedOperationException("Cannot unwrap EMF to " + type, e);
} Prevention
- Remember the split: EntityManager.unwrap for Session, EntityManagerFactory.unwrap for factory/metamodel
- Unwrap to the stable public interfaces (SessionFactory, Metamodel) rather than internals unless required
- After jakarta migration, purge stale javax.persistence imports so unwrap targets match
When it happens
Trigger: Calling emf.unwrap(SomeClass.class) with a type outside Hibernate's supported set — e.g. unwrap(DataSource.class), unwrap(Session.class) (sessions come from EntityManager.unwrap, not the factory), or a class from a different JPA provider. Each branch in unwrap() does type.isInstance(...) and the final else throws.
Common situations: Copy-pasted unwrap(Session.class) or unwrap(Connection.class) code intended for EntityManager; portability layers that unwrap to provider-specific classes; using the older javax vs jakarta EntityManagerFactory class object after a Jakarta migration.
Related errors
- Wrong kind of binder for annotation type: '%s' does not acce
- Unable to unwrap to {}
- immutable global instance of LockOptions
- 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/f816113d6e983033.
Report an issue: GitHub.