aeron-io/aeron · error · ClusterException

replicationChannel must be set

Error message

replicationChannel must be set

What it means

The consensus module needs a replication channel for the archive to stream recording segments between cluster members. conclude() validates that the configured replicationChannel is non-null and throws ClusterException otherwise.

Solutions

  1. Set context.replicationChannel("aeron:udp?endpoint=<host>:<port>") with a unique port per member.
  2. Or call Context.replicationChannel(...) via the configuration property the container reads (aeron.cluster.replication.channel).
  3. Confirm the channel is free/unique per node in multi-node clusters to avoid port conflicts.

Example fix

// before
ConsensusModule.Context ctx = new ConsensusModule.Context()
    .archiveContext(archiveCtx); // no replication channel
// after
ConsensusModule.Context ctx = new ConsensusModule.Context()
    .archiveContext(archiveCtx)
    .replicationChannel("aeron:udp?endpoint=localhost:8040");
Defensive patterns

Strategy: validation

Validate before calling

if (ctx.replicationChannel() == null) {
    throw new IllegalArgumentException("replicationChannel must be configured, e.g. aeron:udp?endpoint=host:port");
}

Prevention

When it happens

Trigger: ConsensusModule.Context.replicationChannel() was never set (null) at launch time — typically when building the context programmatically and omitting replicationChannel(...).

Common situations: Hand-rolling cluster node context instead of using ClusteredServiceContainer defaults; upgrading Aeron where a previously optional field became required; copying an old sample configuration.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModule.java:2093

                    .controlResponseChannel(AeronArchive.Configuration.localControlChannel())
                    .controlRequestStreamId(AeronArchive.Configuration.localControlStreamId())
                    .controlResponseStreamId(
                        clusterId * 100 + 100 + AeronArchive.Configuration.controlResponseStreamId());
            }

            if (!archiveContext.controlRequestChannel().startsWith(CommonContext.IPC_CHANNEL))
            {
                throw new ClusterException("local archive control must be IPC");
            }

            if (!archiveContext.controlResponseChannel().startsWith(CommonContext.IPC_CHANNEL))
            {
                throw new ClusterException("local archive control must be IPC");
            }

            if (null == replicationChannel)
            {
                throw new ClusterException("replicationChannel must be set");
            }

            archiveContext
                .aeron(aeron)
                .errorHandler(null) // ensure that exceptions are re-thrown
                .ownsAeronClient(false)
                .lock(NoOpLock.INSTANCE)
                .controlRequestChannel(addAliasIfAbsent(
                archiveContext.controlRequestChannel(),
                "cm-archive-ctrl-req-cluster-" + clusterId + "-member-" + clusterMemberId))
                .controlResponseChannel(addAliasIfAbsent(
                archiveContext.controlResponseChannel(),
                "cm-archive-ctrl-resp-cluster-" + clusterId + "-member-" + clusterMemberId))
                .clientName(agentRoleName);

            if (null == terminationHook)
            {
                terminationHook = () -> {};

View on GitHub (pinned to 6d60124e15)