{"record":{"id":"e3ef4667c0a02859","repo":"hibernate/hibernate-orm","slug":"jta-transactionmanager-rollback-failed","errorCode":null,"errorMessage":"JTA TransactionManager.rollback() failed","messagePattern":"JTA TransactionManager\\.rollback\\(\\) failed","errorType":"exception","errorClass":"TransactionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionAdapterTransactionManagerImpl.java","lineNumber":81,"sourceCode":"\t\t\tthrow new TransactionException( \"JTA TransactionManager.commit() failed\", e );\n\t\t}\n\t}\n\n\t@Override\n\tpublic void rollback() {\n\t\ttry {\n\t\t\tif ( initiator ) {\n\t\t\t\tinitiator = false;\n\t\t\t\tJTA_LOGGER.callingTransactionManagerRollback();\n\t\t\t\ttransactionManager.rollback();\n\t\t\t\tJTA_LOGGER.calledTransactionManagerRollback();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmarkRollbackOnly();\n\t\t\t}\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new TransactionException( \"JTA TransactionManager.rollback() failed\", e );\n\t\t}\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic TransactionStatus getStatus() {\n\t\ttry {\n\t\t\tfinal var status = StatusTranslator.translate( transactionManager.getStatus() );\n\t\t\tif ( status == null ) {\n\t\t\t\tthrow new TransactionException( \"TransactionManager reported transaction status as unknown\" );\n\t\t\t}\n\t\t\treturn status;\n\t\t}\n\t\tcatch (SystemException e) {\n\t\t\tthrow new TransactionException( \"JTA TransactionManager#getStatus failed\", e );\n\t\t}\n\t}\n","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionAdapterTransactionManagerImpl.java#L63-L99","documentation":"TransactionManager.rollback() threw while executing Transaction.rollback(); wrapped causes are usually SystemException or IllegalStateException, for example when the transaction already completed (a TM timeout finished it, or the container rolled it back) or rollback is invoked from a non-owner thread. Hibernate only calls rollback when it was the initiator - otherwise it marks rollback-only. This exception says the explicit rollback could not complete; the original business error, if any, is separate.","triggerScenarios":"tx.rollback() after the JTA transaction already finished (timeout fired between the failure and the rollback call, container completed it); rollback invoked from a different thread; TM internal error.","commonSituations":"JTA timeout completing the transaction underneath the application; asynchronous processing moving transaction work across threads; TM in recovery.","solutions":["Check tx.getStatus() before rolling back and skip when the transaction is already completed","Increase the JTA transaction timeout if transactions complete before the rollback call","Keep begin, commit and rollback on the same thread","If SystemException persists, check TransactionManager health and logs"],"exampleFix":"// before\ntry { tx.commit(); }\ncatch (Exception e) { tx.rollback(); } // may throw if tx already completed\n\n// after\ntry { tx.commit(); }\ncatch (Exception e) {\n    TransactionStatus st = tx.getStatus();\n    if ( st == TransactionStatus.ACTIVE || st == TransactionStatus.MARKED_ROLLBACK ) {\n        tx.rollback();\n    }\n    else {\n        log.debug(\"transaction already completed; nothing to roll back\", e);\n    }\n}","handlingStrategy":"validation","validationCode":"// Roll back only when the tx is still open\nTransactionStatus st = tx.getStatus();\nif ( st == TransactionStatus.ACTIVE || st == TransactionStatus.MARKED_ROLLBACK ) {\n    tx.rollback();\n}\nelse {\n    log.debug(\"transaction already completed; skipping rollback\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    tx.rollback();\n}\ncatch (TransactionException e) {\n    if ( e.getCause() instanceof IllegalStateException || e.getCause() instanceof SystemException ) {\n        log.warn(\"rollback could not complete; tx may already be gone\", e);\n    }\n}","preventionTips":["Check Transaction.getStatus() before rollback","Set JTA timeouts long enough that transactions do not complete underneath the application","Keep begin/commit/rollback on one thread"],"tags":["jta","transactions","hibernate","rollback"],"backgroundTag":"transaction-rollback-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}