aeron-io/aeron · error · AeronException

Aeron client is closed

Error message

Aeron client is closed

What it means

ClientConductor.ensureActive() is called at the start of every public client operation. When the conductor has been closed (isClosed) it throws AeronException("Aeron client is closed") — after a client is closed all its resources (publications, subscriptions, counters) are released and no further commands are accepted. Calling into Aeron after Aeron.close() (or after the client driver has force-closed the conductor) produces this error.

Solutions

  1. Coordinate shutdown: stop all producer/consumer threads and join them before calling aeron.close().
  2. Guard client access with an application-level 'running' flag so no calls happen after close.
  3. Check aeron.isClosed() (or hold the client behind a lifecycle manager) before submitting new commands.
  4. Create a fresh Aeron instance if you genuinely need to reconnect after close — clients are not reusable.
  5. Catch AeronException in background threads and treat it as a shutdown signal rather than an error.

Example fix

// before
executor.shutdown();
aeron.close();
// publisher thread still running:
publication.offer(buffer); // AeronException: Aeron client is closed

// after
running.set(false);
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS); // let publishers drain
aeron.close();
Defensive patterns

Strategy: try-catch

Validate before calling

if (aeron.isClosed()) {
    return; // or recreate the client
}

Type guard

boolean usable(Aeron aeron) {
    return aeron != null && !aeron.isClosed();
}

Try / catch

try {
    publication.offer(buffer);
} catch (AeronException e) {
    if (e.getMessage().contains("client is closed")) {
        // expected during shutdown: stop the worker loop
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: Using an Aeron instance, or any of its Publications/Subscriptions/Counters, after calling aeron.close(); submitting async commands (addCounter, addPublication) from another thread while shutdown is in progress; agent shutdown hooks or Spring/other lifecycle containers closing Aeron while application threads still publish.

Common situations: Graceful shutdown races: one thread closes Aeron while publisher threads continue sending; reusing a cached Aeron client after an application restart within the same JVM (e.g. hot redeploy); error-handling paths that close the client then attempt cleanup via the same client; tests closing a shared client in @AfterEach while async work continues.

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/26f5fd4c9c7e80eb. Report an issue: GitHub.

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/ClientConductor.java:1715

            final long registrationId = driverProxy.rejectImage(correlationId, position, reason);
            awaitResponse(registrationId);
        }
        finally
        {
            clientLock.unlock();
        }
    }

    void onNextAvailableSessionId(final int nextSessionId)
    {
        lastResponseValue = nextSessionId;
    }

    private void ensureActive()
    {
        if (isClosed)
        {
            throw new AeronException("Aeron client is closed");
        }

        if (isTerminating)
        {
            throw new AeronException("Aeron client is terminating");
        }
    }

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

    private LogBuffers logBuffers(final long registrationId, final String logFileName, final String channel)
    {

View on GitHub (pinned to 6d60124e15)