{"record":{"id":"027be33eef8e78e9","repo":"quarkusio/quarkus","slug":"cannot-register-synchronization","errorCode":null,"errorMessage":"Cannot register synchronization","messagePattern":"Cannot register synchronization","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/context/TransactionContext.java","lineNumber":209,"sourceCode":"            throw new RuntimeException(\"Error getting the current transaction\", e);\n        }\n    }\n\n    /**\n     * Representing of the context state. It's a container for all available beans in the context.\n     * It's filled during bean usage and cleared on destroy.\n     */\n    private static class TransactionContextState implements ContextState, Synchronization {\n\n        private final Lock lock = new ReentrantLock();\n\n        private final ConcurrentMap<Contextual<?>, ContextInstanceHandle<?>> mapBeanToInstanceHandle = new ConcurrentHashMap<>();\n\n        TransactionContextState(Transaction transaction) {\n            try {\n                transaction.registerSynchronization(this);\n            } catch (RollbackException | SystemException e) {\n                throw new RuntimeException(\"Cannot register synchronization\", e);\n            }\n        }\n\n        /**\n         * Put the contextual bean and its handle to the container.\n         *\n         * @param bean bean to be added\n         * @param handle handle for the bean which incorporates the bean, contextual instance and the context\n         */\n        <T> void put(Contextual<T> bean, ContextInstanceHandle<T> handle) {\n            mapBeanToInstanceHandle.put(bean, handle);\n        }\n\n        /**\n         * Remove the bean from the container.\n         *\n         * @param bean contextual bean instance\n         */","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/context/TransactionContext.java#L191-L227","documentation":"When the first bean is created in a transaction scope, Quarkus's TransactionContextState registers a Synchronization with the active JTA transaction so beans can be destroyed at commit/rollback. This error wraps RollbackException or SystemException from Transaction.registerSynchronization(). RollbackException means the transaction is already marked rollback-only (or rolled back), so no new synchronizations can be accepted; SystemException means the transaction service failed.","triggerScenarios":"Creating a @TransactionScoped bean (constructing TransactionContextState) while the current transaction is marked rollback-only, has already rolled back, or is in a state that rejects synchronization registration.","commonSituations":"A prior operation in the same transaction setRollbackOnly() or threw and marked the TX rollback-only, then code lazily instantiates a @TransactionScoped bean; long transactions where the reaper rolled the TX back before a bean is created; entity/session usage after a commit failure.","solutions":["Check transaction status before creating transaction-scoped resources; resolve whatever marked the TX rollback-only earlier in the request","Shorten transaction duration so the reaper (default 60s timeout) doesn't roll it back mid-use","Look at earlier exceptions in the request — the rollback was usually caused by an earlier failure","Increase @TransactionConfiguration(timeout) at the transaction entry point if legitimatedly long"],"exampleFix":"// before: lazy bean creation deep in a doomed TX\n@TransactionScoped Bean b = lookup.getBean().create(...); // throws here\n// after: create beans early, or fail fast on rollback-only\nif (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) throw new TransactionRolledBackException();","handlingStrategy":"try-catch","validationCode":"int status = transactionManager.getStatus();\nboolean canRegisterBeans = (status == jakarta.transaction.Status.STATUS_ACTIVE);","typeGuard":null,"tryCatchPattern":"try { createTxScopedBean(); } catch (RuntimeException e) {\n    if (e.getCause() instanceof RollbackException) { /* TX already rollback-only: surface original failure */ }\n    throw e;\n}","preventionTips":["Fail fast: surface the first exception that marked the TX rollback-only instead of continuing","Instantiate @TransactionScoped beans early in the transaction","Keep transactions short to avoid reaper aborts mid-scope","Never swallow exceptions that called setRollbackOnly earlier in the flow"],"tags":["jta","transaction","synchronization","narayana"],"backgroundTag":"transaction-marked-rollback-only","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}