aeron-io/aeron · error · ArchiveException
failed to send replay request
Error message
failed to send replay request
What it means
startReplay issues a REPLAY control request via ArchiveProxy.replay. The proxy returns false when the control-request publication is not connected or the offer fails, meaning the replay request never reached the archive. The client throws this ArchiveException before polling for the replay session id.
Solutions
- Confirm the archive is running and the control channel is connected.
- Re-establish the AeronArchive session and retry startReplay.
- Retry with backoff for transient backpressure on the control stream.
- Verify replayChannel/replayStreamId arguments before retrying to rule out client-side config errors.
Example fix
// before
long sessionId = archive.startReplay(recordingId, pos, len, replayChannel, streamId);
// after
long sessionId;
try {
sessionId = archive.startReplay(recordingId, pos, len, replayChannel, streamId);
} catch (ArchiveException e) {
archive = AeronArchive.connect(archiveCtx);
sessionId = archive.startReplay(recordingId, pos, len, replayChannel, streamId);
} Defensive patterns
Strategy: retry
Validate before calling
// validate inputs and connectivity before startReplay
if (recordingId <= 0 || length < 0) throw new IllegalArgumentException("bad replay args");
try (AeronArchive ignored = AeronArchive.connect(archiveCtx)) {} Type guard
boolean connected(AeronArchive a) { return a != null && !a.isClosed() && a.state() == AeronArchive.State.CONNECTED; } Try / catch
try {
long sid = archive.startReplay(recordingId, pos, len, ch, streamId);
} catch (ArchiveException e) {
archive = AeronArchive.connect(archiveCtx);
retryWithBackoff(() -> archive.startReplay(recordingId, pos, len, ch, streamId));
} Prevention
- Health-check the archive before replay pipelines start.
- Retry transient send failures with backoff.
- Keep control-channel config in sync between client and archive.
- Avoid sharing one control session across many threads under heavy load.
When it happens
Trigger: Calling startReplay(recordingId, position, length, replayChannel, replayStreamId) with the archive control channel disconnected, backpressured, or the control session publication closed (archive restart, network fault).
Common situations: Replay pipelines started right after archive failover; replayChannel URI typos causing downstream failures that cascade into control-channel disconnects; long-running clients whose control session timed out.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- failed to send bounded replay request
- failed to send stop replay request
- failed to send stop all replays request
- failed to fetch remote recording descriptor
- failed to resolve subscription endpoint: channel=" +…
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/7ebbbeef0d06cff9.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/client/AeronArchive.java:1046
{
lock.lock();
try
{
ensureConnected();
ensureNotReentrant();
lastCorrelationId = aeron.nextCorrelationId();
if (!archiveProxy.replay(
recordingId,
position,
length,
replayChannel,
replayStreamId,
lastCorrelationId,
controlSessionId))
{
throw new ArchiveException("failed to send replay request");
}
return pollForResponse(lastCorrelationId);
}
finally
{
lock.unlock();
}
}
/**
* Start a replay for a length in bytes of a recording from a position bounded by a position counter.
* If the position is {@link #NULL_POSITION} then the stream will be replayed from the start.
* <p>
* The lower 32-bits of the returned value contains the {@link Image#sessionId()} of the received replay. All
* 64-bits are required to uniquely identify the replay when calling {@link #stopReplay(long)}. The lower 32-bits
* can be obtained by casting the {@code long} value to an {@code int}.
*View on GitHub (pinned to 6d60124e15)