quarkusio/quarkus · error · RuntimeException

Cannot register synchronization

Error message

Cannot register synchronization

What it means

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.

Source

Thrown at extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/context/TransactionContext.java:209

            throw new RuntimeException("Error getting the current transaction", e);
        }
    }

    /**
     * Representing of the context state. It's a container for all available beans in the context.
     * It's filled during bean usage and cleared on destroy.
     */
    private static class TransactionContextState implements ContextState, Synchronization {

        private final Lock lock = new ReentrantLock();

        private final ConcurrentMap<Contextual<?>, ContextInstanceHandle<?>> mapBeanToInstanceHandle = new ConcurrentHashMap<>();

        TransactionContextState(Transaction transaction) {
            try {
                transaction.registerSynchronization(this);
            } catch (RollbackException | SystemException e) {
                throw new RuntimeException("Cannot register synchronization", e);
            }
        }

        /**
         * Put the contextual bean and its handle to the container.
         *
         * @param bean bean to be added
         * @param handle handle for the bean which incorporates the bean, contextual instance and the context
         */
        <T> void put(Contextual<T> bean, ContextInstanceHandle<T> handle) {
            mapBeanToInstanceHandle.put(bean, handle);
        }

        /**
         * Remove the bean from the container.
         *
         * @param bean contextual bean instance
         */

View on GitHub (pinned to e1c734241f)

Solutions

  1. Check transaction status before creating transaction-scoped resources; resolve whatever marked the TX rollback-only earlier in the request
  2. Shorten transaction duration so the reaper (default 60s timeout) doesn't roll it back mid-use
  3. Look at earlier exceptions in the request — the rollback was usually caused by an earlier failure
  4. Increase @TransactionConfiguration(timeout) at the transaction entry point if legitimatedly long

Example fix

// before: lazy bean creation deep in a doomed TX
@TransactionScoped Bean b = lookup.getBean().create(...); // throws here
// after: create beans early, or fail fast on rollback-only
if (tx.getStatus() == Status.STATUS_MARKED_ROLLBACK) throw new TransactionRolledBackException();
Defensive patterns

Strategy: try-catch

Validate before calling

int status = transactionManager.getStatus();
boolean canRegisterBeans = (status == jakarta.transaction.Status.STATUS_ACTIVE);

Try / catch

try { createTxScopedBean(); } catch (RuntimeException e) {
    if (e.getCause() instanceof RollbackException) { /* TX already rollback-only: surface original failure */ }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/027be33eef8e78e9. Report an issue: GitHub.