hibernate/hibernate-orm · error · IllegalStateException
Resource-local transaction already active
Error message
Resource-local transaction already active
What it means
The non-JPA branch of TransactionImpl.begin(): when a transaction is already active, jpaCompliance is off, and the coordinator is not JTA (resource-local JDBC), Hibernate still refuses a second begin() with IllegalStateException. Native mode is only slightly more lenient than JPA mode — it never silently joins an existing resource-local transaction.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionImpl.java:74
}
@Override
public void begin() {
if ( !session.isOpen() ) {
throw new IllegalStateException( "Cannot begin Transaction on closed Session/EntityManager" );
}
if ( transactionDriverControl == null ) {
transactionDriverControl =
transactionCoordinator.getTransactionDriverControl();
}
if ( isActive() ) {
if ( jpaCompliance ) {
throw new IllegalStateException( "Transaction already active (in JPA compliant mode)" );
}
else if ( !transactionCoordinator.getTransactionCoordinatorBuilder().isJta() ) {
throw new IllegalStateException( "Resource-local transaction already active" );
}
}
else {
CORE_LOGGER.beginningTransaction();
transactionDriverControl.begin();
}
}
@Override
public void commit() {
// allow MARKED_ROLLBACK to propagate through to transactionDriverControl
if ( !isActive() ) {
// we have a transaction that is inactive and has not been marked for rollback only
throw new IllegalStateException( "Transaction not successfully started" );
}
else {
CORE_LOGGER.committingTransaction();
try {View on GitHub (pinned to fad1729dce)
Solutions
- Reuse the current transaction: keep the Transaction from the first begin() or check session.getTransaction().isActive() before calling begin() again
- Restructure nested calls so exactly one layer owns begin/commit (template-method or try-with-resources pattern)
- Ensure exception paths still commit or roll back, so no active transaction leaks into the next begin()
Example fix
// before
Transaction tx = session.beginTransaction();
processBatchPart1();
Transaction tx2 = session.beginTransaction(); // resource-local -> IllegalStateException
// after
Transaction tx = session.getTransaction();
if (!tx.isActive()) {
tx = session.beginTransaction();
}
processBatchPart1(); Defensive patterns
Strategy: validation
Validate before calling
Transaction tx = session.getTransaction();
if (!tx.isActive()) {
tx = session.beginTransaction();
} Prevention
- One layer owns transaction demarcation; pass the Transaction down instead of re-beginning
- Use session.getTransaction() to detect an in-progress transaction before beginning
- Guarantee commit/rollback in finally so no active transaction leaks
When it happens
Trigger: session.beginTransaction() called twice in native Hibernate mode with a resource-local (JDBC) transaction coordinator and no commit/rollback between the calls; the second call sees isActive() and a non-JTA coordinator and throws.
Common situations: Defensive begin() calls in utility/service methods that call each other; batch loops that begin per iteration when a commit path is skipped on exception; migration from JTA to resource-local datasources where join semantics were expected.
Related errors
- Transaction already active (in JPA compliant mode)
- Illegal attempt to specify a SynchronizationType when buildi
- Newer version [" + latestVersion + "] of entity [" + infoStr
- Unable to locate current JTA transaction
- Calling method '{methodName}' is not valid without an active
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/acc342a499c29491.
Report an issue: GitHub.