{"record":{"id":"447d790cc386a071","repo":"aeron-io/aeron","slug":"response-publication-is-closed-session","errorCode":null,"errorMessage":"response publication is closed: \" + session","messagePattern":"response publication is closed: \" \\+ session","errorType":"exception","errorClass":"ArchiveEvent","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/ControlResponseProxy.java","lineNumber":253,"sourceCode":"            checkResult(session, position);\n        }\n        while (--attempts > 0);\n\n        return false;\n    }\n\n    private static void checkResult(final ControlSession session, final long result)\n    {\n        if (result == Publication.NOT_CONNECTED)\n        {\n            session.abort(ControlSession.RESPONSE_NOT_CONNECTED_MSG);\n            throw new ArchiveEvent(ControlSession.RESPONSE_NOT_CONNECTED_MSG + \": \" + session);\n        }\n\n        if (result == Publication.CLOSED)\n        {\n            session.abort(\"control response publication is closed\");\n            throw new ArchiveEvent(\"response publication is closed: \" + session, AeronException.Category.ERROR);\n        }\n\n        if (result == Publication.MAX_POSITION_EXCEEDED)\n        {\n            session.abort(\"control response publication is at max position\");\n            throw new ArchiveEvent(\n                \"response publication is at max position: \" + session, AeronException.Category.ERROR);\n        }\n    }\n\n    private void logSendResponse(final DirectBuffer buffer, final int offset, final int length)\n    {\n        ArchiveTracing.traceControlResponse(buffer, offset, length);\n    }\n\n    private void logSendSignal(final DirectBuffer buffer, final int offset, final int length)\n    {\n        ArchiveTracing.traceRecordingSignal(buffer, offset, length);","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/ControlResponseProxy.java#L235-L271","documentation":"ControlResponseProxy.checkResult throws ArchiveEvent (Category.ERROR) when the control response publication offer returns Publication.CLOSED, meaning the response publication has been closed and no further control responses can be sent on this session. The session is aborted as part of the throw.","triggerScenarios":"Calling sendDescriptor, sendResponse, or send on ControlResponseProxy after the session's response Publication was closed (session shutdown, conductor closing the session, or explicit close of the control session/publication).","commonSituations":"Archive conductor closed the control session (timeout or client disconnect) while a send was still queued on another thread; race between session close and a final response; archive shutdown in progress while requests still arriving.","solutions":["Do not use a control session after it has been closed; check session state (isClosed) before sending responses","Fix races where conductor close and response sends overlap; serialize sends through the conductor thread as Aeron requires","On the client, reconnect with a new control session since the old response publication cannot be revived","Review shutdown ordering so pending responses are flushed before the session is closed"],"exampleFix":"// before\nif (!controlSession.isClosed())\n{\n    controlResponseProxy.sendResponse(...);\n}\nelse\n{\n    controlResponseProxy.sendResponse(...); // throws: publication closed\n}\n// after\nif (!controlSession.isClosed())\n{\n    controlResponseProxy.sendResponse(...);\n}\nelse\n{\n    // skip response; session already terminated\n}","handlingStrategy":"type-guard","validationCode":"if (controlSession == null || controlSession.isClosed()) { return; /* skip send; session terminated */ }","typeGuard":"boolean canSend(ControlSession s) { return s != null && !s.isClosed(); }","tryCatchPattern":"try { proxy.sendDescriptor(correlationId, descriptorBuffer); }\ncatch (ArchiveEvent e)\n{\n    if (e.getMessage().startsWith(\"response publication is closed\")) { /* session dead: stop sending */ }\n    else { throw e; }\n}","preventionTips":["Check session.isClosed() before every send on a possibly terminated session","Route all response sends through the archive conductor thread to avoid close races","Flush pending responses before closing sessions during shutdown","Treat a closed response publication as permanent: create a new session rather than retrying"],"tags":["java","aeron-archive","publication","closed-resource","lifecycle"],"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"}