{"record":{"id":"c2b9532924b904fa","repo":"hibernate/hibernate-orm","slug":"cannot-roll-back-transaction-in-current-status","errorCode":null,"errorMessage":"Cannot roll back transaction in current status [","messagePattern":"Cannot roll back transaction in current status \\[","errorType":"exception","errorClass":"TransactionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionImpl.java","lineNumber":124,"sourceCode":"\t\t}\n\t\telse {\n\t\t\treturn transactionDriverControl;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void rollback() {\n\t\tif ( !isActive() && jpaCompliance ) {\n\t\t\tthrow new IllegalStateException( \"rollback() called on inactive transaction (in JPA compliant mode)\" );\n\t\t}\n\n\t\tfinal var status = getStatus();\n\t\tif ( status == TransactionStatus.ROLLED_BACK || status == TransactionStatus.NOT_ACTIVE ) {\n\t\t\t// allow rollback() on completed transaction as noop\n\t\t\tCORE_LOGGER.rollbackCalledOnInactiveTransaction();\n\t\t}\n\t\telse if ( !status.canRollback() ) {\n\t\t\tthrow new TransactionException( \"Cannot roll back transaction in current status [\" + status.name() + \"]\" );\n\t\t}\n\t\telse if ( status != TransactionStatus.FAILED_COMMIT || allowFailedCommitToPhysicallyRollback() ) {\n\t\t\tCORE_LOGGER.rollingBackTransaction();\n\t\t\tinternalGetTransactionDriverControl().rollback();\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isActive() {\n\t\tif ( transactionDriverControl == null ) {\n\t\t\tif ( session.isOpen() ) {\n\t\t\t\ttransactionDriverControl =\n\t\t\t\t\t\ttransactionCoordinator.getTransactionDriverControl();\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/TransactionImpl.java#L106-L142","documentation":"rollback() no-ops only for ROLLED_BACK and NOT_ACTIVE; for everything else it checks TransactionStatus.canRollback(), which is true only for ACTIVE, MARKED_ROLLBACK, and FAILED_COMMIT. Statuses such as COMMITTED, COMMITTING, or ROLLING_BACK cannot be rolled back, so a TransactionException names the offending status.","triggerScenarios":"tx.rollback() after tx.commit() succeeded (status COMMITTED); rollback attempted while a commit is in progress (COMMITTING) or while another rollback is already running (ROLLING_BACK); synchronization callbacks trying to roll back mid-commit.","commonSituations":"Catch blocks that run after a successful commit and roll back 'to be safe'; post-commit listeners throwing exceptions that trigger a generic rollback path; concurrent error handling around a completing transaction.","solutions":["Check the status before rolling back: if (tx.getStatus().canRollback()) tx.rollback();","Do not touch the transaction after commit() returns — start a new transaction if compensating work is needed","Order cleanup logic so commit is the final step and later failures cannot reach the transaction object"],"exampleFix":"// before\ntry {\n    tx.commit();\n    notifyListeners();\n} catch (RuntimeException e) {\n    tx.rollback(); // status COMMITTED -> TransactionException\n}\n\n// after\ntry {\n    tx.commit();\n} catch (RuntimeException e) {\n    if (tx.getStatus().canRollback()) {\n        tx.rollback();\n    }\n    throw e;\n}\nnotifyListeners();","handlingStrategy":"validation","validationCode":"org.hibernate.resource.transaction.spi.TransactionStatus st = tx.getStatus();\nif (st == org.hibernate.resource.transaction.spi.TransactionStatus.ROLLED_BACK\n        || st == org.hibernate.resource.transaction.spi.TransactionStatus.NOT_ACTIVE) {\n    // Hibernate no-ops these; nothing to do\n} else if (st.canRollback()) {\n    tx.rollback();\n} else {\n    log.warn(\"Cannot roll back transaction in status {}\", st);\n}","typeGuard":null,"tryCatchPattern":"try {\n    tx.rollback();\n} catch (TransactionException e) {\n    if (String.valueOf(e.getMessage()).startsWith(\"Cannot roll back transaction\")) {\n        // commit already finished or is in flight — nothing to undo\n        log.warn(\"Rollback skipped: {}\", e.getMessage());\n    } else {\n        throw e;\n    }\n}","preventionTips":["Check tx.getStatus().canRollback() before rolling back in shared error handlers","Never call rollback after a successful commit — use a compensating transaction instead","Keep commit as the final statement of the transactional scope"],"tags":["hibernate","transaction","rollback","status","invalid-state"],"backgroundTag":"invalid-transaction-status","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}