aeron-io/aeron · error · ArchiveException

failed to send replicate request

Error message

failed to send replicate request

What it means

Thrown when a replicate request could not be offered to the archive control publication. ArchiveProxy.replicate returned false after retrying the offer, so the archive never received the instruction to replicate the source recording. This signals a control-session/transport failure rather than a replication configuration problem.

Solutions

  1. Re-establish the archive session (AeronArchive.connect) and retry the replicate call.
  2. Validate srcControlChannel is reachable from the destination archive before calling replicate.
  3. Check the Aeron error log and archive logs for publication connection failures or back-pressure; fix channel config accordingly.
  4. Add retry with backoff around replicate when operating over WAN links.
  5. Confirm both source and destination archives are running compatible Aeron versions.

Example fix

// before
long replicationId = archive.replicate(srcRecordingId, AeronArchive.NULL_POSITION, srcControlStreamId, srcControlChannel, null);
// after
long replicationId;
try {
    replicationId = archive.replicate(srcRecordingId, AeronArchive.NULL_POSITION, srcControlStreamId, srcControlChannel, null);
} catch (ArchiveException e) {
    if (e.message().contains("failed to send")) {
        archive = reconnect(archive);
        replicationId = archive.replicate(srcRecordingId, AeronArchive.NULL_POSITION, srcControlStreamId, srcControlChannel, null);
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (archive == null || archive.context().isClosed()) { archive = AeronArchive.connect(ctx); } // and verify srcControlChannel reachable

Type guard

static boolean isSendFailure(ArchiveException e) { return e.getMessage() != null && e.getMessage().contains("failed to send"); }

Try / catch

try { long id = archive.replicate(src, dst, srcStreamId, srcChannel, liveDest); } catch (ArchiveException e) { if (isSendFailure(e)) { archive = reconnect(archive); /* retry once */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling AeronArchive.replicate(srcRecordingId, dstRecordingId, srcControlStreamId, srcControlChannel, liveDestination) while the control session is closed, the archive is unreachable, or the publication is back-pressured past the retry limit.

Common situations: Source archive control channel (srcControlChannel) unreachable at replication setup time; archive restarting; cross-datacenter control channel with high latency causing persistent back-pressure; stale AeronArchive handle reused after session expiry.

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


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/28fe155c04944f03. Report an issue: GitHub.

Appendix: source

Thrown at aeron-archive/src/main/java/io/aeron/archive/client/AeronArchive.java:1829

    {
        lock.lock();
        try
        {
            ensureConnected();
            ensureNotReentrant();

            lastCorrelationId = aeron.nextCorrelationId();

            if (!archiveProxy.replicate(
                srcRecordingId,
                dstRecordingId,
                srcControlStreamId,
                srcControlChannel,
                liveDestination,
                lastCorrelationId,
                controlSessionId))
            {
                throw new ArchiveException("failed to send replicate request");
            }

            return pollForResponse(lastCorrelationId);
        }
        finally
        {
            lock.unlock();
        }
    }

    /**
     * Replicate a recording from a source archive to a destination which can be considered a backup for a primary
     * archive. The source recording will be replayed via the provided replay channel and use the original stream id.
     * If the destination recording id is {@link io.aeron.Aeron#NULL_VALUE} then a new destination recording is created,
     * otherwise the provided destination recording id will be extended. The details of the source recording
     * descriptor will be replicated.
     * <p>
     * For a source recording that is still active the replay can merge with the live stream and then follow it

View on GitHub (pinned to 6d60124e15)