aeron-io/aeron · error · AeronException
registration id is not a Subscription
Error message
registration id is not a Subscription: <simpleName>
What it means
Thrown by ClientConductor when removing a subscription by registration id and the id maps to an existing resource that is neither a Subscription nor a PendingSubscription. The conductor keeps resource type checks symmetric with removePublication to prevent releasing the wrong object.
Solutions
- Use the registration id from the Subscription (or its future) returned by addSubscription.
- Call removePublication/removeCounter for non-subscription ids.
- Keep ids in typed wrappers (e.g. record SubscriptionHandle(long regId)) to prevent mix-ups.
Example fix
// before long id = client.addPublication(channel, streamId).registrationId(); client.removeSubscription(id); // AeronException // after long subId = client.addSubscription(channel, streamId).registrationId(); client.removeSubscription(subId);
Defensive patterns
Strategy: try-catch
Validate before calling
if (!(resource instanceof Subscription)) throw new IllegalStateException("id is not a subscription");
client.removeSubscription(subscription.registrationId()); Type guard
boolean isSubscriptionRegId(long regId) { Object r = resourceByRegId(regId); return r instanceof Subscription || r instanceof PendingSubscription; } Try / catch
try { client.removeSubscription(regId); } catch (AeronException e) { log.warn("reg id {} is not a Subscription: {}", regId, e.getMessage()); } Prevention
- Pair each add call with its matching remove call in the same scope.
- Name id variables after their resource type.
- Keep a typed handle class around Subscription/Publication ids.
When it happens
Trigger: Calling removeSubscription(subscriptionRegistrationId) with an id belonging to a Publication, Counter, or image-related registration.
Common situations: Storing ids in generic long variables or collections; concurrency refactors that shuffle which id is which; logging/telemetry code echoing the wrong id back into remove calls.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- registration id is not a Publication
- expected format is ' ' or ' :port', but got
- key length out of bounds
- label length exceeds MAX_LABEL_LENGTH: <label.length()>
- label length out of bounds
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/8146d6b79152b052.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-client/src/main/java/io/aeron/ClientConductor.java:861
}
}
void removeSubscription(final long subscriptionRegistrationId)
{
clientLock.lock();
try
{
if (NULL_VALUE == subscriptionRegistrationId || isTerminating || isClosed)
{
return;
}
ensureNotReentrant();
final Object resource = resourceByRegIdMap.get(subscriptionRegistrationId);
if (resource != null && !(resource instanceof PendingSubscription || resource instanceof Subscription))
{
throw new AeronException("registration id is not a Subscription: " +
resource.getClass().getSimpleName());
}
final Subscription subscription = resource instanceof PendingSubscription ?
((PendingSubscription)resource).subscription : (Subscription)resource;
if (null != subscription)
{
resourceByRegIdMap.remove(subscriptionRegistrationId);
subscription.internalClose(EXPLICIT_CLOSE_LINGER_NS);
}
if (asyncCommandIdSet.remove(subscriptionRegistrationId) || null != subscription)
{
asyncCommandIdSet.add(driverProxy.removeSubscription(subscriptionRegistrationId));
}
}
finally
{View on GitHub (pinned to 6d60124e15)