hibernate/hibernate-orm · error · IllegalStateException

Transaction was not properly begun/started

Error message

Transaction was not properly begun/started

What it means

internalGetTransactionDriverControl() returns the TransactionDriver that drives the physical transaction; the field is populated lazily by begin()/isActive() when the session is open. The method exists (per its comment) to turn a confusing NullPointerException into a descriptive IllegalStateException when driver-dependent operations run before the transaction was begun.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionImpl.java:105

			// 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 {
				internalGetTransactionDriverControl().commit();
			}
			catch (RuntimeException e) {
				throw session.getExceptionConverter().convertCommitException( e );
			}
		}
	}

	@Nonnull
	public TransactionDriver internalGetTransactionDriverControl() {
		// NOTE here to help be a more descriptive NullPointerException
		if ( transactionDriverControl == null ) {
			throw new IllegalStateException( "Transaction was not properly begun/started" );
		}
		else {
			return transactionDriverControl;
		}
	}

	@Override
	public void rollback() {
		if ( !isActive() && jpaCompliance ) {
			throw new IllegalStateException( "rollback() called on inactive transaction (in JPA compliant mode)" );
		}

		final var status = getStatus();
		if ( status == TransactionStatus.ROLLED_BACK || status == TransactionStatus.NOT_ACTIVE ) {
			// allow rollback() on completed transaction as noop
			CORE_LOGGER.rollbackCalledOnInactiveTransaction();
		}
		else if ( !status.canRollback() ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Begin the transaction first: use session.beginTransaction() (begins immediately) before setTimeout() or other driver-dependent calls
  2. Check tx.isActive() before touching driver-backed operations
  3. Create the Transaction lazily, right before the work, rather than holding an un-begun reference across the request

Example fix

// before
Transaction tx = session.getTransaction();
tx.setTimeout(30); // driver not created yet -> IllegalStateException
tx.begin();

// after
Transaction tx = session.beginTransaction(); // begin() creates the driver
tx.setTimeout(30);
Defensive patterns

Strategy: validation

Validate before calling

if (!tx.isActive()) {
    tx = session.beginTransaction();
}
tx.setTimeout(30); // driver exists only after begin

Prevention

When it happens

Trigger: Invoking any operation routed through the driver before begin(): commit()/rollback()/markRollbackOnly() paths on a never-begun Transaction, or a setTimeout()/similar call made on a Transaction object obtained but not started.

Common situations: Setting a transaction timeout before begin(); unit tests driving TransactionImpl directly without begin(); error handling that calls markRollbackOnly()/rollback() although begin() never ran.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/931aaac13167468e. Report an issue: GitHub.