{"record":{"id":"d81c2f9a6db36215","repo":"aeron-io/aeron","slug":"recording-events-publication-is-closed","errorCode":null,"errorMessage":"recording events publication is closed","messagePattern":"recording events publication is closed","errorType":"exception","errorClass":"ArchiveException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/RecordingEventsProxy.java","lineNumber":143,"sourceCode":"\n                bufferClaim.commit();\n                break;\n            }\n            else if (Publication.NOT_CONNECTED == position)\n            {\n                break;\n            }\n\n            checkResult(position, publication);\n        }\n        while (--attempts > 0);\n    }\n\n    private static void checkResult(final long position, final Publication publication)\n    {\n        if (position == Publication.CLOSED)\n        {\n            throw new ArchiveException(\"recording events publication is closed\");\n        }\n\n        if (position == Publication.MAX_POSITION_EXCEEDED)\n        {\n            throw new ArchiveException(\n                \"recording events publication at max position, term-length=\" + publication.termBufferLength());\n        }\n    }\n}\n","sourceCodeStart":125,"sourceCodeEnd":153,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/RecordingEventsProxy.java#L125-L153","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Treat this as terminal for the events stream: stop offering events and recreate the publication/subscriber pair.","Ensure subscribers to the recording events channel remain connected so the archive keeps the publication open.","Do not call started/progress/stopped after RecordingEventsProxy.close(); check isClosed() first.","If seen during shutdown, guard event emission with the archive agent's lifecycle state."],"exampleFix":"// before\nproxy.progress(recordingId, position);\n// after\nif (!proxy.isClosed()) {\n    proxy.progress(recordingId, position);\n}","handlingStrategy":"try-catch","validationCode":"if (proxy.isClosed() || publication.isClosed()) { /* recreate before offering */ }","typeGuard":null,"tryCatchPattern":"try { proxy.progress(recId, pos); }\ncatch (ArchiveException e) {\n    if (e.getMessage().contains(\"publication is closed\")) {\n        recreateEventsPublication();\n    }\n}","preventionTips":["Keep at least one subscriber on the recording events channel.","Close RecordingEventsProxy only at final shutdown and stop emitting afterwards.","Check isClosed() before every offer in long-running agents."],"tags":["publication-closed","archive","lifecycle","shutdown"],"backgroundTag":"invalid-state-transition","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}