{"record":{"id":"df373846ebec67c9","repo":"quarkusio/quarkus","slug":"transaction-rolled-back-due-to","errorCode":null,"errorMessage":"Transaction rolled back due to: ","messagePattern":"Transaction rolled back due to: ","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/reactive-transactions/runtime/src/main/java/io/quarkus/reactive/transaction/runtime/TransactionalInterceptorBase.java","lineNumber":123,"sourceCode":"    }\n\n    private Uni<Void> invokeBeforeCommitAndCommit(Context context) {\n        return reactiveResource.beforeCommit(context)\n                .onItem().invoke(() -> LOG.tracef(\"Flushed the session before commit/rollback\"))\n                .onItemOrFailure().call((result, exception) -> {\n                    if (exception != null) {\n                        Uni<SqlConnection> connectionUni = connectionFromContext();\n                        if (connectionUni == null) {\n                            LOG.tracef(\"Transaction doesn't exist, cannot rollback, propagating original exception\");\n                            return Uni.createFrom().failure(\n                                    new RuntimeException(\"Transaction rolled back due to: \", exception));\n                        }\n                        return connectionUni\n                                .onItem()\n                                .transformToUni(connection -> actualRollback(connection.transaction(), exception).invoke(() -> {\n                                    // onItemOrFailure() will still propagate the chain even with an execption\n                                    // we need to rethrow it to make sure the reactive chain fails\n                                    throw new RuntimeException(\"Transaction rolled back due to: \", exception);\n                                }));\n                    } else {\n                        return commit();\n                    }\n                }).replaceWithVoid();\n    }\n\n    private Uni<?> closeConnection() {\n        Future<Void> closeFuture = TransactionalContextPool.closeAndClearCurrentConnection();\n        if (closeFuture == null) {\n            // io/quarkus/hibernate/reactive/transaction/DisableJTATransactionTest.java:38\n            LOG.tracef(\"Connection doesn't exist, nothing to do here\");\n            return Uni.createFrom().nullItem();\n        }\n        return toUni(closeFuture)\n                .invoke(connection -> LOG.tracef(\"Closing the connection %s\", connection));\n    }\n","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/reactive-transactions/runtime/src/main/java/io/quarkus/reactive/transaction/runtime/TransactionalInterceptorBase.java#L105-L141","documentation":"When an exception escapes a reactive @Transactional method, the interceptor rolls back the transaction and rethrows a RuntimeException(\"Transaction rolled back due to: \", exception) to force the reactive chain to fail. It signals that the DB transaction was rolled back because of the wrapped cause.","triggerScenarios":"A reactive @Transactional method's Uni chain fails (e.g. constraint violation, query error), or rollback is triggered by rollbackOrCommitBasedOnException after commit preparation fails.","commonSituations":"Unique/constraint violations on persist; serialization failures; a downstream service call inside a transaction throwing; misconfigured datasource causing commit/rollback failures.","solutions":["Inspect the wrapped cause (getCause()) to fix the actual DB failure, e.g. duplicate keys or constraint violations.","Add @ReactiveTransactional only where needed and handle expected failures in the Uni chain with onFailure/recoverWithItem.","If commits fail systematically, verify datasource connectivity and transaction configuration (quarkus.datasource.*, quarkus.hibernate-orm.*)."],"exampleFix":"// before\nclient.query(...).chain(unchecked(this::save)) // exception bubbles as rolled-back RuntimeException\n// after\nreturn client.query(...).chain(this::save)\n    .onFailure(DuplicateKeyException.class, f -> log.warn(\"dup\"))\n    .onItem().transform(x -> Response.ok(x).build());","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return service.save(entity).await().indefinitely();\n} catch (RuntimeException e) {\n    Throwable cause = e.getCause();\n    log.error(\"tx rolled back: {}\", cause != null ? cause.getMessage() : e.getMessage());\n    throw cause instanceof RuntimeException ? (RuntimeException) cause : e;\n}","preventionTips":["Always inspect getCause() of rolled-back exceptions","Handle expected DB failures (constraint violations) in the Uni chain via onFailure","Validate uniqueness before persisting in transactions","Keep transactions short and avoid external calls inside them"],"tags":["quarkus","transactions","reactive","rollback"],"backgroundTag":"transaction-rolled-back","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}