aeron-io/aeron · error · TimeoutException
failed to fetch remote recording descriptor
Error message
failed to fetch remote recording descriptor
What it means
Thrown by ReplicationSession.replicateDescriptor when, after successfully sending a listRecording request to the source archive, the recording descriptor poller receives zero fragments for longer than actionTimeoutMs, so the remote recording descriptor never arrives. Aeron throws TimeoutException to abort a replication whose source archive is not answering descriptor queries. It is a driver-side timeout of an in-flight archive control request, not a lookup miss (a missing recording is reported separately as 'unknown src recording id').
Solutions
- Verify the source archive is reachable and its conductor is alive (check source archive logs for the listRecording request).
- Increase the replication/connect timeout in the Archive client context (actionTimeoutMs / archive context timeouts) to cover the actual network RTT.
- Ensure the control request/response channel configuration matches on source and destination and the network path is reliable (consider reliable/TCP control streams or fix packet loss).
- Retry the replication; if it always times out at the same step, capture both archives' logs and check descriptor poller activity.
- Upgrade Aeron — replication session timeout handling has been tuned across releases.
Example fix
// before
final ArchiveClientContext ctx = new ArchiveClientContext()
.aeron(aeron);
// after: give the replication session a longer control timeout on slow links
final ArchiveClientContext ctx = new ArchiveClientContext()
.aeron(aeron)
.connectTimeoutNs(TimeUnit.SECONDS.toNanos(30)); Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: confirm the source recording exists and the archive responds
try (AeronArchive probe = AeronArchive.connect(ctx)) {
if (!probe.listRecording(srcRecordingId, (c, i) -> {})) {
throw new IllegalStateException("src recording " + srcRecordingId + " not found on source archive");
}
} Type guard
boolean sourceArchiveReachable(AeronArchive src) {
return src != null && src.controlResponsePoller().subscription().isConnected();
} Try / catch
try {
replicationSession.doWork();
} catch (TimeoutException e) {
if (e.getMessage().contains("failed to fetch remote recording descriptor")) {
log.warn("source archive did not answer descriptor query; retrying with longer timeout");
scheduleRetryWithBackoff();
}
} Prevention
- Verify the source recording id exists via listRecording before starting replication.
- Size actionTimeoutMs larger than the worst-case control RTT between the two archives.
- Monitor source archive conductor health and control-channel connectivity.
- Alert on control request/response gaps so stalls are caught before replication timeouts.
When it happens
Trigger: Calling AeronArchive.startReplication/replicate (or replicate with live merge) where the source archive accepts the listRecording subscription offer but never publishes the descriptor: source archive conductor stalled or dead, control-channel loss (UDP drops on an unreliable control stream), source recording list backing up, or actionTimeoutMs (aeron.archive.replication.connect.timeout style context) too small for a loaded archive.
Common situations: Replicating across WAN links with default timeouts; source archive paused by long GC or swapped out; control request/response channels misconfigured (different control endpoints than the replication channel) so responses never return; heavy archive load delaying the conductor; network partitions between source and destination clusters.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- failed to send recording position request
- failed to get recording position
- failed to resolve subscription endpoint: channel=" +…
- failed to list remote recording descriptor
- cannot live merge without active source recording
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/c3a8ff0bf00f399e.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/ReplicationSession.java:475
{
throw new TimeoutException("failed to list remote recording descriptor");
}
}
else
{
final RecordingDescriptorPoller poller = srcArchive.recordingDescriptorPoller();
final int fragments = poller.poll();
if (poller.isDispatchComplete() && poller.remainingRecordCount() > 0)
{
final String errorMsg = "unknown src recording id " + srcRecordingId;
state(State.DONE, errorMsg);
error(errorMsg, ArchiveException.UNKNOWN_RECORDING);
}
if (0 == fragments && epochClock.time() >= (timeOfLastActionMs + actionTimeoutMs))
{
throw new TimeoutException("failed to fetch remote recording descriptor");
}
workCount += fragments;
}
return workCount;
}
private int srcRecordingPosition()
{
int workCount = 0;
if (NULL_VALUE == activeCorrelationId)
{
final long correlationId = aeron.nextCorrelationId();
final long controlSessionId = srcArchive.controlSessionId();
if (srcArchive.archiveProxy().getRecordingPosition(srcRecordingId, correlationId, controlSessionId))
{View on GitHub (pinned to 6d60124e15)