quarkusio/quarkus · error · IllegalStateException

Syncs are not allowed because the group of synchronizations

Error message

Syncs are not allowed because the group of synchronizations to which this sync belongs has already ran

What it means

Quarkus's AgroalOrderedLastSynchronizationList registers JTA synchronizations in ordered groups; each group tracks whether it already ran (FINISHED) during the two-phase completion. Adding a synchronization to a group that already executed is illegal, so add() throws this IllegalStateException. This happens when a datasource/connection proxy tries to register its cleanup sync after beforeCompletion/afterCompletion has started.

Source

Thrown at extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/internal/tsr/AgroalOrderedLastSynchronizationList.java:60

     *
     * The beforeCompletion methods within a group are called in the order they were added,
     * and the afterCompletion methods are ran in the reverse order
     */
    private class SynchronizationGroup implements Synchronization {
        String packagePrefix; // Synchronizations with this package prefix belong to this group
        final List<Synchronization> synchs; // the Synchronizations in the group
        volatile ExecutionStatus status; // track the status to decide when it's too late to allow more registrations

        public SynchronizationGroup(String packagePrefix) {
            this.packagePrefix = packagePrefix;
            this.synchs = new ArrayList<>();
            this.status = ExecutionStatus.PENDING;
        }

        public void add(Synchronization synchronization) {
            if (status == ExecutionStatus.FINISHED) {
                // this group of syncs have already ran
                throw new IllegalStateException(ADD_SYNC_ERROR);
            }
            synchs.add(synchronization);
        }

        @Override
        public void beforeCompletion() {
            status = ExecutionStatus.RUNNING;

            // Note that because synchronizations can register other synchronizations
            // we cannot use enhanced for loops as that could cause a concurrency exception
            for (int i = 0; i < synchs.size(); i++) {
                Synchronization sync = synchs.get(i);

                try {
                    sync.beforeCompletion();
                } catch (Exception e) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debugf(

View on GitHub (pinned to e1c734241f)

Solutions

  1. Ensure all resources are enlisted before the transaction reaches the completing state — don't open new connections during beforeCompletion
  2. Move registration earlier in the transactional work (before the last business call)
  3. Audit custom Synchronization/InterposedSynchronization code that registers other syncs from completion callbacks
  4. Upgrade Quarkus if you suspect a resource-late-enlistment bug in an extension (known issues fixed over time)

Example fix

// before: registering a sync inside beforeCompletion
public void beforeCompletion() { list.add(mySync); } // FINISHED group -> throws
// after: register at TX start, not during completion
txManager.getTransaction().registerSynchronization(mySync); // early
Defensive patterns

Strategy: validation

Validate before calling

// register synchronizations only while TX is active
if (transactionManager.getStatus() != jakarta.transaction.Status.STATUS_ACTIVE) {
    throw new IllegalStateException("Too late to enlist synchronization");
}

Try / catch

try { registerLateSync(); } catch (IllegalStateException e) {
    if (e.getMessage().contains("Syncs are not allowed")) { log.warn("Late sync skipped", e); }
}

Prevention

When it happens

Trigger: Calling add(synchronization) on a SynchronizationList whose status == FINISHED — i.e. registerInterposedSynchronization is invoked for a group that already ran during transaction completion (between beforeCompletion and afterCompletion, or after completion).

Common situations: Acquiring a new DB connection from a resource already involved in the TX during the completion phase; lazy resources registering interceptors late; code in beforeCompletion opening new enlisted resources; custom Synchronization registration triggered from within another synchronization callback.

Related errors


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