aeron-io/aeron · error · ControlProtocolException

UNKNOWN_PUBLICATION

UNKNOWN_PUBLICATION

Error message

unknown publication: ${registrationId}

What it means

Thrown by Aeron's DriverConductor when a client asks the driver to remove (or revoke) a publication whose registrationId does not match any active PublicationLink in the driver. The driver tracks every publication by the registrationId returned at addPublication time; a remove command only succeeds for a still-live publication. This is a ControlProtocolException with code UNKNOWN_PUBLICATION delivered back to the requesting client.

Solutions

  1. Verify you pass the exact registrationId returned by the addPublication future (Publication.registrationId()) and remove each publication at most once
  2. Track publication lifecycle: ignore UNKNOWN_PUBLICATION on cleanup paths, treating it as 'already gone' rather than a failure
  3. Check the driver is the same instance the publication was added to (driver was not restarted or clustered away)
  4. Enable driver event log (aeron.driver.event.log) to confirm when the publication link was removed and by whom

Example fix

// before
try { aeron.removePublication(publication.registrationId()); } catch (ControlProtocolException e) { throw e; }
// after
long regId = publication.registrationId();
try {
    aeron.removePublication(regId);
} catch (ControlProtocolException e) {
    if (e.errorCode() == ControlProtocolException.Code.UNKNOWN_PUBLICATION) {
        // publication already closed/reaped - treat as success on cleanup path
    } else { throw e; }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (publication.isClosed()) { return; } // publication already gone, skip removal
final long regId = publication.registrationId();

Type guard

boolean isKnownPublication(Aeron aeron, long registrationId) { return registrationId > 0 && !publication.isClosed(); }

Try / catch

try {
    aeron.removePublication(regId);
} catch (ControlProtocolException e) {
    if (e.errorCode() != ControlProtocolException.Code.UNKNOWN_PUBLICATION) throw e;
    // idempotent: publication already removed or reaped
}

Prevention

When it happens

Trigger: Calling Aeron.removePublication() (or driver control removePublication with revoke=true) with a registrationId that was never added, was already removed, or belonged to a publication closed when its client timed out.

Common situations: Double-removing the same publication; using a stale registrationId after a driver restart or client keepalive timeout reaped the publication; mixing up publication vs counter/subscription registration ids; caching ids across a driver reconnection.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at aeron-driver/src/main/java/io/aeron/driver/DriverConductor.java:764

    void onRemovePublication(final long registrationId, final long correlationId, final boolean revoke)
    {
        PublicationLink publicationLink = null;
        final ArrayList<PublicationLink> publicationLinks = this.publicationLinks;
        for (int i = 0, size = publicationLinks.size(); i < size; i++)
        {
            final PublicationLink publication = publicationLinks.get(i);
            if (registrationId == publication.registrationId())
            {
                publicationLink = publication;
                fastUnorderedRemove(publicationLinks, i);
                break;
            }
        }

        if (null == publicationLink)
        {
            throw new ControlProtocolException(UNKNOWN_PUBLICATION, "unknown publication: " + registrationId);
        }

        if (revoke)
        {
            publicationLink.revoke();
        }
        publicationLink.close();
        clientProxy.operationSucceeded(correlationId);
    }

    void onAddSendDestination(final long registrationId, final String destinationChannel, final long correlationId)
    {
        scheduleClientCommand(new AddSendDestinationCommand(registrationId, destinationChannel, correlationId));
    }

    void onRemoveSendDestination(final long registrationId, final String destinationChannel, final long correlationId)
    {
        scheduleClientCommand(new RemoveSendDestinationCommand(registrationId, destinationChannel, correlationId));

View on GitHub (pinned to 6d60124e15)