{"record":{"id":"3b7e0e1585d98890","repo":"aeron-io/aeron","slug":"failed-to-resolve-subscription-endpoint-channel","errorCode":null,"errorMessage":"failed to resolve subscription endpoint: channel=\" + recordingSubscription.channel()","messagePattern":"failed to resolve subscription endpoint: channel=\" \\+ recordingSubscription\\.channel\\(\\)","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java","lineNumber":677,"sourceCode":"\n        responseArchiveProxy = new ArchiveProxy(responsePublication);\n        state(State.REPLAY, \"ArchiveProxy created\");\n\n        return workCount;\n    }\n\n    private int replay()\n    {\n        int workCount = 0;\n\n        if (NULL_VALUE == activeCorrelationId)\n        {\n            final String resolvedEndpoint = recordingSubscription.resolvedEndpoint();\n            if (null == resolvedEndpoint)\n            {\n                if (epochClock.time() >= (timeOfLastActionMs + actionTimeoutMs))\n                {\n                    throw new TimeoutException(\n                        \"failed to resolve subscription endpoint: channel=\" + recordingSubscription.channel());\n                }\n\n                return workCount;\n            }\n\n            final ChannelUri channelUri = ChannelUri.parse(replicationChannel);\n            final String endpoint = channelUri.get(CommonContext.ENDPOINT_PARAM_NAME);\n            if (null != endpoint)\n            {\n                channelUri.replaceEndpointWildcardPort(resolvedEndpoint);\n            }\n\n            if (null != liveDestination)\n            {\n                channelUri.put(CommonContext.LINGER_PARAM_NAME, \"0\");\n                channelUri.put(CommonContext.EOS_PARAM_NAME, \"false\");\n            }","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java#L659-L695","documentation":"Thrown by ReplicationSession.replay when the destination-side recording subscription exists but Subscription.resolvedEndpoint() is still null after actionTimeoutMs — the transport never bound the subscription to a concrete local address (typically with dynamic/multi-destination or wildcard ports). Aeron fails the replication because the source archive cannot be told a replay destination without a resolved endpoint. The exception message includes the subscription's channel URI for diagnosis.","triggerScenarios":"Replication using multicast or MDC/manual multicast with a wildcard (0.0.0.0:0 style) endpoint where the subscription never resolves; firewall blocking the bind; destination URI missing/incorrect endpoint or control params so no address is ever resolved; OS-level failure to bind the socket within the timeout.","commonSituations":"Wildcard endpoints combined with control-mode=manual misconfigurations; cloud/firewall setups blocking UDP binds or MDC control traffic; typos in the replication channel URI (missing endpoint attribute); host lacking a routable interface so resolution never completes.","solutions":["Check the replication channel URI: provide a concrete endpoint (or correct MDC control/response params) instead of a wildcard that never resolves.","Verify with the OS (ss/netstat) that the subscription socket actually bound; look for firewall/SELinux blocks on the UDP port.","Ensure MDC control-mode and control/response addresses are consistent when using multicast live merges.","Increase the action timeout if endpoint resolution is merely slow in your environment.","Test connectivity with a simple Aeron subscriber on the same channel URI to confirm it resolves an endpoint."],"exampleFix":"// before: wildcard endpoint that never resolves\nAeronArchive.replicate(archive, srcRecordingId, \"aeron:udp?endpoint=0.0.0.0:0\", streamId, srcCtl, srcRep);\n// after: explicit endpoint\nAeronArchive.replicate(archive, srcRecordingId, \"aeron:udp?endpoint=10.1.2.3:40456\", streamId, srcCtl, srcRep);","handlingStrategy":"try-catch","validationCode":"// resolve the channel first and confirm a concrete endpoint exists\nChannelUri uri = ChannelUri.parse(replicationChannel);\nString endpoint = uri.get(CommonContext.ENDPOINT_PARAM_NAME);\nif (endpoint == null && !uri.hasControlModeResponse()) {\n    throw new IllegalArgumentException(\"replication channel needs an endpoint or MDC control-mode=response\");\n}","typeGuard":"boolean endpointResolved(Subscription sub) {\n    return sub != null && sub.isConnected() && sub.resolvedEndpoint() != null;\n}","tryCatchPattern":"try {\n    runReplication();\n} catch (TimeoutException e) {\n    if (e.getMessage().contains(\"failed to resolve subscription endpoint\")) {\n        log.error(\"subscription never resolved on channel {}; check endpoint/firewall/MDC config\", channel);\n        abortReplication();\n    }\n}","preventionTips":["Use explicit endpoints (host:port) in replication channels rather than wildcards unless MDC is correctly configured.","Verify with ss/netstat that the UDP port can bind; clear firewall/SELinux blocks.","Keep MDC control-mode/control/response parameters consistent across source and destination.","Smoke-test the exact channel URI with a plain Aeron subscriber before wiring it into replication."],"tags":["aeron","archive","replication","endpoint","network"],"backgroundTag":"connection-refused","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"}