aeron-io/aeron · error · ArchiveException

recording events publication is closed

Error message

recording events publication is closed

What it means

RecordingEventsProxy publishes recording-started/progress/stopped notifications on an exclusive publication. checkResult inspects the offer position: Publication.CLOSED means the recording events publication has been closed and no notification can be sent, so an ArchiveException is thrown.

Solutions

  1. Treat this as terminal for the events stream: stop offering events and recreate the publication/subscriber pair.
  2. Ensure subscribers to the recording events channel remain connected so the archive keeps the publication open.
  3. Do not call started/progress/stopped after RecordingEventsProxy.close(); check isClosed() first.
  4. If seen during shutdown, guard event emission with the archive agent's lifecycle state.

Example fix

// before
proxy.progress(recordingId, position);
// after
if (!proxy.isClosed()) {
    proxy.progress(recordingId, position);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (proxy.isClosed() || publication.isClosed()) { /* recreate before offering */ }

Try / catch

try { proxy.progress(recId, pos); }
catch (ArchiveException e) {
    if (e.getMessage().contains("publication is closed")) {
        recreateEventsPublication();
    }
}

Prevention

When it happens

Trigger: started(), progress(), or stopped() attempts to offer an event after the underlying recording events Publication was closed — typically because the archive agent is shutting down or the publication was explicitly closed.

Common situations: Archive shutting down while a recording completes; subscribers disconnecting causing the archive to close the events publication; calling RecordingEventsProxy methods after its own close(); driver teardown during reconfiguration.

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

Appendix: source

Thrown at aeron-archive/src/main/java/io/aeron/archive/RecordingEventsProxy.java:143

                bufferClaim.commit();
                break;
            }
            else if (Publication.NOT_CONNECTED == position)
            {
                break;
            }

            checkResult(position, publication);
        }
        while (--attempts > 0);
    }

    private static void checkResult(final long position, final Publication publication)
    {
        if (position == Publication.CLOSED)
        {
            throw new ArchiveException("recording events publication is closed");
        }

        if (position == Publication.MAX_POSITION_EXCEEDED)
        {
            throw new ArchiveException(
                "recording events publication at max position, term-length=" + publication.termBufferLength());
        }
    }
}

View on GitHub (pinned to 6d60124e15)