hibernate/hibernate-orm · error · IllegalStateException
Transaction is not accessible when using JTA with JPA-compli
Error message
Transaction is not accessible when using JTA with JPA-compliant transaction access enabled
What it means
JPA forbids EntityManager.getTransaction() when transactions are JTA-managed, unless the provider option allows it. Hibernate computes this in isTransactionAccessible(): access is blocked when JTA is in use, JPA transaction compliance is enabled, and hibernate.jta.allowTransactionAccess (JtaTransactionAccessEnabled, default false in JPA bootstrap) is not set. getTransaction() then throws IllegalStateException instead of handing out an unusable Transaction object.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java:1334
if ( !factoryOptions.isAllowOutOfTransactionUpdateOperations()
&& !isTransactionInProgress() ) {
throw new TransactionRequiredException( exceptionMessage );
}
}
private boolean isTransactionAccessible() {
// JPA requires that access not be provided to the transaction when using JTA.
// This is overridden when SessionFactoryOptions isJtaTransactionAccessEnabled() is true.
return factoryOptions.isJtaTransactionAccessEnabled() // defaults to false in JPA bootstrap
|| !factoryOptions.getJpaCompliance().isJpaTransactionComplianceEnabled()
|| !factory.transactionCoordinatorBuilder.isJta();
}
@Override
@Nonnull
public Transaction getTransaction() throws HibernateException {
if ( !isTransactionAccessible() ) {
throw new IllegalStateException(
"Transaction is not accessible when using JTA with JPA-compliant transaction access enabled"
);
}
return accessTransaction();
}
@Override
@Nonnull
public Transaction accessTransaction() {
checkSessionReentrancy();
if ( currentHibernateTransaction == null ) {
currentHibernateTransaction = new TransactionImpl( getTransactionCoordinator(), this );
}
if ( isOpenOrWaitingForAutoClose() ) {
transactionCoordinator.pulse();
}
return currentHibernateTransaction;
}View on GitHub (pinned to fad1729dce)
Solutions
- Use JTA demarcation instead: @Transactional (Jakarta/Spring) or UserTransaction begin/commit — never em.getTransaction() under JTA.
- If legacy behavior must be kept, set hibernate.jta.allowTransactionAccess=true to re-enable resource-local style access.
- Or configure the persistence unit as RESOURCE_LOCAL where you genuinely control transactions yourself.
Example fix
// before (JTA environment)
em.getTransaction().begin(); // IllegalStateException
// after
@Transactional
public void transfer(...) { ... }
// or manual JTA:
userTransaction.begin(); try { ...; userTransaction.commit(); } catch (Exception e) { userTransaction.rollback(); } Defensive patterns
Strategy: validation
Validate before calling
// Detect JTA up front and use the right demarcation style
boolean jta = ((SessionFactoryImplementor) emf).getOptions()
.getJpaCompliance().isJpaTransactionComplianceEnabled()
&& ((SessionFactoryImplementor) emf).getTransactionCoordinatorBuilder().isJta();
if (jta) {
userTransaction.begin(); // JTA path: never em.getTransaction()
} else {
em.getTransaction().begin(); // resource-local path: OK
} Try / catch
try {
em.getTransaction().begin();
} catch (IllegalStateException e) {
if (e.getMessage().contains("JTA")) {
throw new UnsupportedOperationException("Use UserTransaction/@Transactional under JTA", e);
}
throw e;
} Prevention
- Centralize transaction begin/commit in one helper that knows the environment
- When porting to JTA, grep the codebase for getTransaction() and replace with @Transactional
- Document whether each persistence unit is JTA or RESOURCE_LOCAL next to its config
When it happens
Trigger: Calling em.getTransaction().begin()/commit()/rollback() or session.getTransaction() in a JTA environment (WildFly, WebSphere, Spring with JtaTransactionManager) with default settings — typical in code ported from resource-local deployments (plain Tomcat/Spring default).
Common situations: Porting a resource-local application to an app server or JTA transaction manager; legacy Hibernate-native code using session.getTransaction(); toggling hibernate.jpa.compliance settings during JPA certification; framework tests using RESOURCE_LOCAL against a JTA-configured PU.
Related errors
- Explicitly joining a JTA transaction requires a JTA transact
- Exception pulsing TransactionCoordinator
- No named stored procedure call with given name '{}'
- Illegal attempt to specify a SynchronizationType when buildi
- Unable to start isolated transaction
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/47dfbbb9d39bceff.
Report an issue: GitHub.