hibernate/hibernate-orm · error · TransactionException
Could not set transaction to rollback only
Error message
Could not set transaction to rollback only
What it means
markRollbackOnly() calls TransactionManager.setRollbackOnly(); a SystemException from the TM is wrapped as 'Could not set transaction to rollback only'. This is the safe path failing after a business error - the transaction may still be active and must be resolved by explicit rollback, timeout, or container intervention. Reached via Transaction.markRollbackOnly(), and via rollback() when Hibernate was not the initiator (which falls back to marking rollback-only).
Source
Thrown at hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionAdapterTransactionManagerImpl.java:106
try {
final var status = StatusTranslator.translate( transactionManager.getStatus() );
if ( status == null ) {
throw new TransactionException( "TransactionManager reported transaction status as unknown" );
}
return status;
}
catch (SystemException e) {
throw new TransactionException( "JTA TransactionManager#getStatus failed", e );
}
}
@Override
public void markRollbackOnly() {
try {
transactionManager.setRollbackOnly();
}
catch (SystemException e) {
throw new TransactionException( "Could not set transaction to rollback only", e );
}
}
@Override
public void setTimeOut(int seconds) {
if ( seconds > 0 ) {
try {
transactionManager.setTransactionTimeout( seconds );
}
catch (SystemException e) {
throw new TransactionException( "Unable to apply requested transaction timeout", e );
}
}
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Check TransactionManager.getStatus() before marking rollback-only
- Inspect the SystemException cause in the TM logs
- If Hibernate initiated the transaction, call rollback() directly instead of markRollbackOnly()
- Restart the TM if it is unhealthy
Defensive patterns
Strategy: validation
Validate before calling
// Mark rollback-only only inside an active transaction
if ( session.getTransaction().getStatus() == TransactionStatus.ACTIVE
|| session.getTransaction().getStatus() == TransactionStatus.MARKED_ROLLBACK ) {
session.getTransaction().markRollbackOnly();
} Try / catch
try {
tx.markRollbackOnly();
}
catch (TransactionException e) {
log.error("could not mark rollback-only; attempting full rollback instead", e);
tx.rollback(); // may succeed where setRollbackOnly failed
} Prevention
- Check transaction status before calling markRollbackOnly()
- Prefer rollback() when your code initiated the transaction
- Treat repeated TM SystemExceptions as an environment incident
When it happens
Trigger: session.getTransaction().markRollbackOnly(), or the rollback() fallback on a non-initiated transaction, while TransactionManager.setRollbackOnly() throws SystemException - TM internal error, TM shutting down, or no usable transaction on the thread.
Common situations: TM internal failure; marking rollback-only with no active JTA transaction; races during application shutdown.
Related errors
- JTA TransactionManager.commit() failed
- JTA UserTransaction.commit() failed
- Unable to mark transaction for rollback only
- Transaction is not accessible when using JTA with JPA-compli
- Exception pulsing TransactionCoordinator
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/84cfde5cbfbd3018.
Report an issue: GitHub.