aeron-io/aeron · error · TimeoutException
failed to resolve subscription endpoint: channel=" +…
Error message
failed to resolve subscription endpoint: channel=" + recordingSubscription.channel()
What it means
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.
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.
Example fix
// before: wildcard endpoint that never resolves AeronArchive.replicate(archive, srcRecordingId, "aeron:udp?endpoint=0.0.0.0:0", streamId, srcCtl, srcRep); // after: explicit endpoint AeronArchive.replicate(archive, srcRecordingId, "aeron:udp?endpoint=10.1.2.3:40456", streamId, srcCtl, srcRep);
Defensive patterns
Strategy: try-catch
Validate before calling
// resolve the channel first and confirm a concrete endpoint exists
ChannelUri uri = ChannelUri.parse(replicationChannel);
String endpoint = uri.get(CommonContext.ENDPOINT_PARAM_NAME);
if (endpoint == null && !uri.hasControlModeResponse()) {
throw new IllegalArgumentException("replication channel needs an endpoint or MDC control-mode=response");
} Type guard
boolean endpointResolved(Subscription sub) {
return sub != null && sub.isConnected() && sub.resolvedEndpoint() != null;
} Try / catch
try {
runReplication();
} catch (TimeoutException e) {
if (e.getMessage().contains("failed to resolve subscription endpoint")) {
log.error("subscription never resolved on channel {}; check endpoint/firewall/MDC config", channel);
abortReplication();
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- failed to fetch remote recording descriptor
- failed to send recording position request
- cannot live merge without active source recording
- failed to get recording position
- failed to send replay request
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/3b7e0e1585d98890.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java:677
responseArchiveProxy = new ArchiveProxy(responsePublication);
state(State.REPLAY, "ArchiveProxy created");
return workCount;
}
private int replay()
{
int workCount = 0;
if (NULL_VALUE == activeCorrelationId)
{
final String resolvedEndpoint = recordingSubscription.resolvedEndpoint();
if (null == resolvedEndpoint)
{
if (epochClock.time() >= (timeOfLastActionMs + actionTimeoutMs))
{
throw new TimeoutException(
"failed to resolve subscription endpoint: channel=" + recordingSubscription.channel());
}
return workCount;
}
final ChannelUri channelUri = ChannelUri.parse(replicationChannel);
final String endpoint = channelUri.get(CommonContext.ENDPOINT_PARAM_NAME);
if (null != endpoint)
{
channelUri.replaceEndpointWildcardPort(resolvedEndpoint);
}
if (null != liveDestination)
{
channelUri.put(CommonContext.LINGER_PARAM_NAME, "0");
channelUri.put(CommonContext.EOS_PARAM_NAME, "false");
}View on GitHub (pinned to 6d60124e15)