{"record":{"id":"c750200b2d4fe899","repo":"quarkusio/quarkus","slug":"calling-a-method-annotated-with-transactional-fro-c75020","errorCode":null,"errorMessage":"Calling a method annotated with @Transactional from a method annotated with @WithTransaction is not supported. Use either @Transactional or @WithSessionOnDemand/@WithSession/@WithTransaction, but not both, throughout your whole application.","messagePattern":"Calling a method annotated with @Transactional from a method annotated with @WithTransaction is not supported\\. Use either @Transactional or @WithSessionOnDemand/@WithSession/@WithTransaction, but not both, throughout your whole application\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"extensions/reactive-transactions/runtime/src/main/java/io/quarkus/reactive/transaction/runtime/TransactionalInterceptorBase.java","lineNumber":279,"sourceCode":"\n    public static boolean reactiveInterceptorShouldRun() {\n        boolean condition = Context.isOnEventLoopThread();\n        LOG.tracef(\"Transactional interceptor should run: %s\", condition);\n        return condition;\n    }\n\n    protected void validateLegacyPanacheAnnotations() {\n        // We are running on the retrieved context, however, the method also switch the safety flag.\n        Context ignored = vertxContext();\n        if (ContextLocals.get(SESSION_ON_DEMAND_KEY).isPresent()) {\n            throw new UnsupportedOperationException(\n                    \"Calling a method annotated with @Transactional from a method annotated with @WithSessionOnDemand is not supported. \"\n                            + \"Use either @Transactional or @WithSessionOnDemand/@WithSession/@WithTransaction, \"\n                            + \"but not both, throughout your whole application.\");\n        }\n\n        if (ContextLocals.get(WITH_TRANSACTION_METHOD_KEY).isPresent()) {\n            throw new UnsupportedOperationException(\n                    \"Calling a method annotated with @Transactional from a method annotated with @WithTransaction is not supported. \"\n                            + \"Use either @Transactional or @WithSessionOnDemand/@WithSession/@WithTransaction, \"\n                            + \"but not both, throughout your whole application.\");\n        }\n\n        if (ContextLocals.get(REACTIVE_TRANSACTIONAL_METHOD_KEY).isPresent()) {\n            throw new UnsupportedOperationException(\n                    \"Calling a method annotated with @Transactional from a method annotated with @ReactiveTransactional is not supported. \"\n                            + \"Use either @Transactional or @WithSessionOnDemand/@WithSession/@WithTransaction, \"\n                            + \"but not both, throughout your whole application.\");\n        }\n    }\n\n    /**\n     *\n     * @return the current vertx duplicated context\n     * @throws IllegalStateException If no vertx context is found or is not a safe context as mandated by the\n     *         {@link VertxContextSafetyToggle}","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/reactive-transactions/runtime/src/main/java/io/quarkus/reactive/transaction/runtime/TransactionalInterceptorBase.java#L261-L297","documentation":"Same family as above: the @Transactional interceptor detects a WITH_TRANSACTION_METHOD_KEY flag left by a legacy @WithTransaction method up the call stack. Mixing legacy Panache @WithTransaction with @Transactional in one call chain is unsupported and throws UnsupportedOperationException.","triggerScenarios":"Calling a @Transactional-annotated method from a method annotated with Panache's @WithTransaction.","commonSituations":"Incremental migration from @WithTransaction to @Transactional; utility methods still using @WithTransaction while services migrated to @Transactional.","solutions":["Replace @WithTransaction with @ReactiveTransactional (or plain @Transactional) on the caller.","Ensure only one transactional annotation family is used across the whole application per the error message.","Audit call graphs so legacy Panache annotations never wrap @Transactional methods."],"exampleFix":"// before\n@WithTransaction\npublic Uni<Order> save(Order o) { return repo.persist(o); }\n// after\n@ReactiveTransactional\npublic Uni<Order> save(Order o) { return repo.persist(o); }","handlingStrategy":"validation","validationCode":"void check(Class<?> bean) {\n    for (Method m : bean.getDeclaredMethods())\n        if (m.isAnnotationPresent(WithTransaction.class) && usesTransactionalServices(bean, m))\n            throw new IllegalStateException(\"@WithTransaction wrapping @Transactional: \" + m);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return service.save(order);\n} catch (UnsupportedOperationException e) {\n    log.error(\"Replace legacy @WithTransaction with @ReactiveTransactional: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Replace @WithTransaction with @ReactiveTransactional during migration","Keep a single transactional annotation family codebase-wide","Enforce with ArchUnit/annotation scanning in CI","Document the chosen style in the team wiki"],"tags":["quarkus","reactive-transactions","panache","annotation-conflict"],"backgroundTag":"transactional-annotation-conflict","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"}