aeron-io/aeron · error · AeronException

Subscription is closed

Error message

Subscription is closed

What it means

Aeron throws this when addDestination() is called on a Subscription that has already been closed. A Subscription's volatile isClosed flag is set during close(); once set, any conductor-bound mutation such as adding a destination is illegal because the client conductor no longer tracks this registrationId. The error signals a lifecycle bug: the caller is using a stale Subscription reference after teardown.

Solutions

  1. Check subscription.isClosed() before calling addDestination and skip or recreate the subscription
  2. Track client lifecycle: call addDestination only while the owning Aeron client is alive (hook ClientConductor/Aeron close callbacks)
  3. Guard all destination management behind a single owner thread or executor so close and addDestination cannot race
  4. Catch AeronException and treat the subscription as dead, then re-create subscription + destination

Example fix

// before
subscription.addDestination("aeron:udp?endpoint=localhost:40456");

// after
if (!subscription.isClosed())
{
    subscription.addDestination("aeron:udp?endpoint=localhost:40456");
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (subscription.isClosed()) { throw new IllegalStateException("subscription closed"); }

Type guard

boolean isUsable(Subscription s) { return s != null && !s.isClosed(); }

Try / catch

try { subscription.addDestination(endpoint); } catch (AeronException e) { if (e.getMessage().contains("closed")) { recreateSubscriptionAndDestinations(); } else { throw e; } }

Prevention

When it happens

Trigger: Calling subscription.addDestination(endpointChannel) after subscription.close() (or after ClientConductor shut down the subscription, e.g. on driver timeout or conductor.close()).

Common situations: Multi-threaded code where one thread closes the client/subscription while another still mutates destinations; reusing a cached Subscription after reconnecting; failing to null out a Subscription field in a shutdown hook.

Related errors


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

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/Subscription.java:474

     *
     * @return {@link List} of local socket addresses for this subscription.
     * @see #channelStatus()
     */
    public List<String> localSocketAddresses()
    {
        return LocalSocketAddressStatus.findAddresses(conductor.countersReader(), channelStatus(), channelStatusId);
    }

    /**
     * Add a destination manually to a multi-destination Subscription.
     *
     * @param endpointChannel for the destination to add.
     */
    public void addDestination(final String endpointChannel)
    {
        if (isClosed)
        {
            throw new AeronException("Subscription is closed");
        }

        conductor.addRcvDestination(registrationId, endpointChannel);
    }

    /**
     * Remove a previously added destination from a multi-destination Subscription.
     *
     * @param endpointChannel for the destination to remove.
     */
    public void removeDestination(final String endpointChannel)
    {
        if (isClosed)
        {
            throw new AeronException("Subscription is closed");
        }

        conductor.removeRcvDestination(registrationId, endpointChannel);

View on GitHub (pinned to 6d60124e15)