aeron-io/aeron · error · ArchiveException

failed to send truncate recording request

Error message

failed to send truncate recording request

What it means

AeronArchive.truncateRecording() throws this ArchiveException when the truncate-recording request could not be offered to the archive control-request publication. archiveProxy.truncateRecording() returned false, meaning the message was not enqueued (publication not connected, closed, or back-pressured for the entire retry window), so pollForResponse never runs and the recording is not truncated.

Solutions

  1. Check that the archive is up and control-channel configuration matches on client and archive.
  2. Retry truncateRecording after a short backoff; transient back-pressure frequently clears.
  3. Reconnect with AeronArchive.connect() if the control session has been closed server-side.
  4. Ensure the recording is stopped and the position is a valid stop position before retrying, so repeated failed offers do not keep filling the buffer.
  5. Inspect archive logs for session timeouts or publication errors preceding this failure.

Example fix

// before
archive.truncateRecording(recordingId, position);

// after
try {
    archive.truncateRecording(recordingId, position);
} catch (ArchiveException e) {
    if (e.getMessage().contains("failed to send truncate recording request")) {
        // archive unreachable or control session dead; reconnect and retry
        try (AeronArchive fresh = AeronArchive.connect(ctx)) {
            fresh.truncateRecording(recordingId, position);
        }
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// ensure the recording is stopped and control channel is connected before truncating
if (!archive.archiveProxy().controlPublication().isConnected()) {
    throw new IllegalStateException("archive control publication not connected");
}
long stopPos = archive.getStopPosition(recordingId);
if (position < 0 || position > stopPos) {
    throw new IllegalArgumentException("truncate position out of range: " + position);
}

Try / catch

try {
    archive.truncateRecording(recordingId, position);
} catch (ArchiveException e) {
    if (e.getMessage().contains("failed to send truncate recording request")) {
        Thread.sleep(backoffMs); // reconnect if the session is dead, then retry
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling truncateRecording(recordingId, position) when the archive control stream cannot accept the request: archive process down, control session expired or closed by the archive, control-request terminal buffer full, or misconfigured control channel.

Common situations: Rewinding a recording to re-consume it while the archive is restarting; long-lived clients whose session was reaped; truncation issued right after a failed replay request that already saturated the control stream.

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/6f3b2dcab518bec6. Report an issue: GitHub.

Appendix: source

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

     * Truncating a recording will stop any concurrent replays of that recording.
     *
     * @param recordingId of the stopped recording to be truncated.
     * @param position    to which the recording will be truncated.
     * @return count of deleted segment files.
     */
    public long truncateRecording(final long recordingId, final long position)
    {
        lock.lock();
        try
        {
            ensureConnected();
            ensureNotReentrant();

            lastCorrelationId = aeron.nextCorrelationId();

            if (!archiveProxy.truncateRecording(recordingId, position, lastCorrelationId, controlSessionId))
            {
                throw new ArchiveException("failed to send truncate recording request");
            }

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


    /**
     * Purge a stopped recording, i.e. mark recording as {@link io.aeron.archive.codecs.RecordingState#INVALID}
     * and delete the corresponding segment files. The space in the Catalog will be reclaimed upon compaction.
     *
     * @param recordingId of the stopped recording to be purged.
     * @return count of deleted segment files.
     */

View on GitHub (pinned to 6d60124e15)