aeron-io/aeron · error · ClusterException
Aeron client must use a RethrowingErrorHandler
Error message
Aeron client must use a RethrowingErrorHandler
What it means
When an external Aeron client is supplied, conclude() verifies that its subscriberErrorHandler is a RethrowingErrorHandler. Subscriber errors in the cluster must propagate to the cluster's error handling rather than being swallowed, so a client configured with a different (e.g. logging) subscriber error handler is rejected with a ClusterException.
Solutions
- Configure the shared Aeron client with .subscriberErrorHandler(RethrowingErrorHandler.INSTANCE)
- Or let the ConsensusModule create its own Aeron client (do not call ctx.aeron(...)) — it installs a rethrowing handler automatically
- Wrap your custom logic outside the subscriber error handler path (e.g. in a distinct client used by other subscriptions)
Example fix
// before
Aeron aeron = Aeron.connect(new Aeron.Context()
.subscriberErrorHandler(err -> log.warn("error", err)));
ctx.aeron(aeron);
// after
Aeron aeron = Aeron.connect(new Aeron.Context()
.subscriberErrorHandler(RethrowingErrorHandler.INSTANCE));
ctx.aeron(aeron); Defensive patterns
Strategy: validation
Validate before calling
if (!(aeron.context().subscriberErrorHandler() instanceof RethrowingErrorHandler)) {
throw new IllegalStateException("shared Aeron client must use RethrowingErrorHandler for the cluster");
} Type guard
boolean usesRethrowingHandler(Aeron aeron) { return aeron.context().subscriberErrorHandler() instanceof RethrowingErrorHandler; } Try / catch
try { ctx.conclude(); } catch (ClusterException e) { if (e.getMessage().contains("RethrowingErrorHandler")) { /* reconnect ctx with a compliant client */ } } Prevention
- Use a dedicated Aeron client for the cluster node
- Never install a swallowing subscriber error handler on the client handed to the ConsensusModule
- Let the ConsensusModule build its own client when possible
When it happens
Trigger: Passing a user-created Aeron client via ctx.aeron(client) where the Aeron.Context had subscriberErrorHandler set to something other than RethrowingErrorHandler.INSTANCE.
Common situations: Sharing an application-wide Aeron client with the cluster after installing a custom subscriber error handler; enabling default Aeron error handling for other subscriptions and reusing the same client for the ConsensusModule.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Aeron client must use a RethrowingErrorHandler
- Aeron client must use a RethrowingErrorHandler
- Aeron client must use conductor agent invoker
- Aeron client must use conductor agent invoker
- error counter must be supplied if aeron client is
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/5483a4648a0785b9.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModule.java:1910
errorCounter = ClusterCounters.allocateVersioned(
aeron,
buffer,
"Cluster Errors",
CONSENSUS_MODULE_ERROR_COUNT_TYPE_ID,
clusterId,
ConsensusModuleVersion.VERSION,
ConsensusModuleVersion.GIT_SHA);
}
}
if (null == ingressChannel)
{
throw new ClusterException("ingressChannel must be specified");
}
if (!(aeron.context().subscriberErrorHandler() instanceof RethrowingErrorHandler))
{
throw new ClusterException("Aeron client must use a RethrowingErrorHandler");
}
if (!aeron.context().useConductorAgentInvoker())
{
throw new ClusterException("Aeron client must use conductor agent invoker");
}
if (null == errorCounter)
{
throw new ClusterException("error counter must be supplied if aeron client is");
}
if (null == countedErrorHandler)
{
countedErrorHandler = new CountedErrorHandler(errorHandler, errorCounter);
if (ownsAeronClient)
{
aeron.context().errorHandler(countedErrorHandler);View on GitHub (pinned to 6d60124e15)