{"record":{"id":"5483a4648a0785b9","repo":"aeron-io/aeron","slug":"aeron-client-must-use-a-rethrowingerrorhandler-5483a4","errorCode":null,"errorMessage":"Aeron client must use a RethrowingErrorHandler","messagePattern":"Aeron client must use a RethrowingErrorHandler","errorType":"validation","errorClass":"ClusterException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModule.java","lineNumber":1910,"sourceCode":"                    errorCounter = ClusterCounters.allocateVersioned(\n                        aeron,\n                        buffer,\n                        \"Cluster Errors\",\n                        CONSENSUS_MODULE_ERROR_COUNT_TYPE_ID,\n                        clusterId,\n                        ConsensusModuleVersion.VERSION,\n                        ConsensusModuleVersion.GIT_SHA);\n                }\n            }\n\n            if (null == ingressChannel)\n            {\n                throw new ClusterException(\"ingressChannel must be specified\");\n            }\n\n            if (!(aeron.context().subscriberErrorHandler() instanceof RethrowingErrorHandler))\n            {\n                throw new ClusterException(\"Aeron client must use a RethrowingErrorHandler\");\n            }\n\n            if (!aeron.context().useConductorAgentInvoker())\n            {\n                throw new ClusterException(\"Aeron client must use conductor agent invoker\");\n            }\n\n            if (null == errorCounter)\n            {\n                throw new ClusterException(\"error counter must be supplied if aeron client is\");\n            }\n\n            if (null == countedErrorHandler)\n            {\n                countedErrorHandler = new CountedErrorHandler(errorHandler, errorCounter);\n                if (ownsAeronClient)\n                {\n                    aeron.context().errorHandler(countedErrorHandler);","sourceCodeStart":1892,"sourceCodeEnd":1928,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModule.java#L1892-L1928","documentation":"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.","triggerScenarios":"Passing a user-created Aeron client via ctx.aeron(client) where the Aeron.Context had subscriberErrorHandler set to something other than RethrowingErrorHandler.INSTANCE.","commonSituations":"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.","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)"],"exampleFix":"// before\nAeron aeron = Aeron.connect(new Aeron.Context()\n    .subscriberErrorHandler(err -> log.warn(\"error\", err)));\nctx.aeron(aeron);\n// after\nAeron aeron = Aeron.connect(new Aeron.Context()\n    .subscriberErrorHandler(RethrowingErrorHandler.INSTANCE));\nctx.aeron(aeron);","handlingStrategy":"validation","validationCode":"if (!(aeron.context().subscriberErrorHandler() instanceof RethrowingErrorHandler)) {\n    throw new IllegalStateException(\"shared Aeron client must use RethrowingErrorHandler for the cluster\");\n}","typeGuard":"boolean usesRethrowingHandler(Aeron aeron) { return aeron.context().subscriberErrorHandler() instanceof RethrowingErrorHandler; }","tryCatchPattern":"try { ctx.conclude(); } catch (ClusterException e) { if (e.getMessage().contains(\"RethrowingErrorHandler\")) { /* reconnect ctx with a compliant client */ } }","preventionTips":["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"],"tags":["configuration","error-handling","aeron-client"],"backgroundTag":"invalid-config-value","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}