aeron-io/aeron · error · ConcurrentConcludeException

ConcurrentConcludeException

Error message

ConcurrentConcludeException

What it means

ClusterBackup.Context.conclude() is guarded against being invoked more than once using an atomic IS_CONCLUDED flag. Calling conclude() (directly or indirectly via conclude/CloseHelper on the same Context) a second time throws ConcurrentConcludeException. Contexts must be concluded exactly once before starting the ClusterBackup.

Solutions

  1. Conclude the Context exactly once, in the single thread that owns ClusterBackup startup.
  2. If reusing a Context after a failed attempt, create a new Context instead of re-concluding the old one.
  3. Guard concurrent startup with application-level synchronization or a boolean flag before calling conclude().
  4. Use try-with-resources/ownership conventions: let ClusterBackup close its own context rather than concluding it manually.

Example fix

// before
ctx.conclude();
clusterBackup = new ClusterBackup(ctx);
ctx.conclude(); // second call -> throws
// after
ctx.conclude(); // only once
clusterBackup = new ClusterBackup(ctx);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!concluded) { ctx.conclude(); concluded = true; }

Type guard

static boolean isConcluded(ClusterBackup.Context ctx) { return ctx != null && ctx.isConcluded(); } // guard via public flag if exposed

Try / catch

try {
    ctx.conclude();
    backup = new ClusterBackup(ctx);
} catch (ConcurrentConcludeException e) {
    throw new IllegalStateException("ClusterBackup context concluded more than once", e);
}

Prevention

When it happens

Trigger: Calling ClusterBackup.Context.conclude() twice on the same Context instance, or concurrent conclusion from two threads (getAndSet wins in one thread and the other throws).

Common situations: Application code concluding the context and then also passing ownership to a helper that concludes it again; launching ClusterBackup from two threads with a shared Context.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/ccd5cdf282bcb8e6. Report an issue: GitHub.

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ClusterBackup.java:685

                return (Context)super.clone();
            }
            catch (final CloneNotSupportedException ex)
            {
                throw new RuntimeException(ex);
            }
        }

        /**
         * Conclude configuration by setting up defaults when specifics are not provided.
         */
        @SuppressWarnings("MethodLength")
        public void conclude()
        {
            final ExpandableArrayBuffer buffer = new ExpandableArrayBuffer();

            if ((boolean)IS_CONCLUDED_VH.getAndSet(this, true))
            {
                throw new ConcurrentConcludeException();
            }

            if (null == clusterDir)
            {
                clusterDir = new File(clusterDirectoryName);
            }
            else
            {
                clusterDirectoryName = clusterDir.getPath();
            }

            if (deleteDirOnStart)
            {
                IoUtil.delete(clusterDir, false);
            }

            if (null == catchupEndpoint)
            {

View on GitHub (pinned to 6d60124e15)