aeron-io/aeron · error · ArchiveException

client is closed

Error message

client is closed

What it means

AeronArchive tracks its connection lifecycle with a State enum. This guard is in the code path that verifies the client is CONNECTED before performing work; if the state is CLOSED, further use is impossible, so the library throws this ArchiveException instead of proceeding on a dead connection.

Solutions

  1. Check AeronArchive.state() / isClosed() before use, or hold a single reference and stop using it after close().
  2. Create a new AeronArchive instance (AeronArchive.connect(ctx)) to replace the closed one.
  3. Reorder shutdown so all archive work completes before close(), and make worker threads observe a shutdown flag.
  4. Catch ArchiveException in the worker loop and treat it as a shutdown signal.

Example fix

// before
archive.startRecording(channel, streamId, SourceLocation.LOCAL); // may be closed
// after
if (archive.isClosed())
{
    archive = AeronArchive.connect(archiveCtx);
}
archive.startRecording(channel, streamId, SourceLocation.LOCAL);
Defensive patterns

Strategy: validation

Validate before calling

if (archive == null || archive.isClosed()) { archive = AeronArchive.connect(archiveCtx.clone()); }

Type guard

boolean usable(AeronArchive a) { return a != null && !a.isClosed(); }

Prevention

When it happens

Trigger: Calling any AeronArchive method (e.g. startRecording, stopRecording, pollForNextResponse) after close() was called on the archive client, or a timeout/error path closed the connection internally.

Common situations: Application shutdown ordering where the archive client is closed while worker threads still use it; catching a connect timeout elsewhere and continuing; reusing an archive client across requests after an error handler closed it.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

    private void dispatchRecordingSignal(final ControlResponsePoller poller)
    {
        context.recordingSignalConsumer().onSignal(
            poller.controlSessionId(),
            poller.correlationId(),
            poller.recordingId(),
            poller.subscriptionId(),
            poller.position(),
            poller.recordingSignal());
    }

    private void ensureConnected()
    {
        final State currentState = state;
        if (State.CONNECTED != currentState)
        {
            if (State.CLOSED == currentState)
            {
                throw new ArchiveException("client is closed");
            }
            else
            {
                close();
            }
        }
    }

    private void ensureNotReentrant()
    {
        if (isInCallback)
        {
            throw new AeronException("reentrant calls not permitted during callbacks");
        }
    }

    private void state(final State newState)
    {

View on GitHub (pinned to 6d60124e15)