{"record":{"id":"e076686bbf60e121","repo":"aeron-io/aeron","slug":"publication-already-added-for-channel-channel-streamid","errorCode":null,"errorMessage":"publication already added for channel=\" + channel + \" streamId=\" + streamId","messagePattern":"publication already added for channel=\" \\+ channel \\+ \" streamId=\" \\+ streamId","errorType":"exception","errorClass":"ArchiveException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/client/AeronArchive.java","lineNumber":621,"sourceCode":"     * This is a sessionId specific recording.\n     *\n     * @param channel  for the publication.\n     * @param streamId for the publication.\n     * @return the {@link Publication} ready for use.\n     */\n    public Publication addRecordedPublication(final String channel, final int streamId)\n    {\n        Publication publication = null;\n        lock.lock();\n        try\n        {\n            ensureConnected();\n            ensureNotReentrant();\n\n            publication = aeron.addPublication(channel, streamId);\n            if (!publication.isOriginal())\n            {\n                throw new ArchiveException(\n                    \"publication already added for channel=\" + channel + \" streamId=\" + streamId);\n            }\n\n            startRecording(ChannelUri.addSessionId(channel, publication.sessionId()), streamId, SourceLocation.LOCAL);\n        }\n        catch (final RuntimeException ex)\n        {\n            CloseHelper.quietClose(publication);\n            throw ex;\n        }\n        finally\n        {\n            lock.unlock();\n        }\n\n        return publication;\n    }\n","sourceCodeStart":603,"sourceCodeEnd":639,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/client/AeronArchive.java#L603-L639","documentation":"addRecordedPublication adds a publication for the given channel/streamId and then asks the archive to record it. Aeron publications have an 'original' flag: only the first publication for a channel+streamId pair in this client is original. If the publication is not original, the same channel/streamId was already added, and the library throws ArchiveException to prevent double-adding a recorded publication.","triggerScenarios":"Calling AeronArchive.addRecordedPublication(channel, streamId) with a channel+streamId for which this Aeron client already created a publication (e.g. calling the method twice, or reusing an existing publication's channel/streamId).","commonSituations":"Application retry logic re-invoking addRecordedPublication after an error without cleanup; two components sharing one Aeron client each attempting to record the same channel/streamId; re-subscribing/re-adding after reconnect without closing prior publications.","solutions":["Call addRecordedPublication only once per channel/streamId per Aeron client; track existing publications before adding","Close the previously created publication before re-adding, or use a distinct session id in the channel URI","Use tryStopRecording/stopRecording and close publications, then retry the add if a duplicate is suspected"],"exampleFix":"// before\narchive.addRecordedPublication(channel, streamId);\narchive.addRecordedPublication(channel, streamId); // throws: publication already added\n// after\nPublication pub = aeron.addPublication(channel, streamId);\nif (!existingRecordings.contains(channel + streamId)) {\n    archive.addRecordedPublication(channel, streamId);\n}","handlingStrategy":"validation","validationCode":"// track channels+streamIds already being recorded by this Aeron client\nif (recordedChannels.contains(channel + \"|\" + streamId)) {\n    return; // already added\n}","typeGuard":null,"tryCatchPattern":"try {\n    archive.addRecordedPublication(channel, streamId);\n} catch (ArchiveException ex) {\n    if (ex.getMessage().startsWith(\"publication already added\")) {\n        // skip: recording already in place\n    }\n}","preventionTips":["Keep one owner per recorded channel/streamId per Aeron client","On retry after failure, close the previously created publication first","Use unique session ids in channel URIs when multiple recordings of the same stream are needed"],"tags":["aeron-archive","duplicate","state-conflict"],"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"}