{"record":{"id":"9d7a55a6c45e7f1d","repo":"aeron-io/aeron","slug":"segment-file-already-exists-file","errorCode":null,"errorMessage":"segment file already exists: \" + file","messagePattern":"segment file already exists: \" \\+ file","errorType":"exception","errorClass":"ArchiveException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/RecordingWriter.java","lineNumber":243,"sourceCode":"        }\n        catch (final IOException ex)\n        {\n            CloseHelper.close(recordingFile);\n            close();\n            LangUtil.rethrowUnchecked(ex);\n        }\n    }\n\n    private void onFileRollOver()\n    {\n        CloseHelper.close(recordingFileChannel);\n        segmentOffset = 0;\n        segmentBasePosition += segmentLength;\n\n        final File file = new File(archiveDir, Archive.segmentFileName(recordingId, segmentBasePosition));\n        if (file.exists())\n        {\n            throw new ArchiveException(\"segment file already exists: \" + file);\n        }\n\n        openRecordingSegmentFile(file);\n    }\n\n    private void checkErrorType(final IOException ex, final int writeLength)\n    {\n        boolean isLowStorageSpace = false;\n        IOException suppressed = null;\n\n        try\n        {\n            isLowStorageSpace = StorageSpaceException.isStorageSpaceError(ex) ||\n                ctx.archiveFileStore().getUsableSpace() < writeLength;\n        }\n        catch (final IOException ex2)\n        {\n            suppressed = ex2;","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/RecordingWriter.java#L225-L261","documentation":"RecordingWriter throws this when rolling over to a new recording segment file and the target segment file already exists in the archive directory. Aeron archive segments are addressed deterministically by recordingId + segmentBasePosition, so a pre-existing file means recorded data would be silently overwritten or the recording log would be inconsistent, so the writer fails fast instead.","triggerScenarios":"onFileRollOver (invoked from onBlock when the segment length is exceeded) computes Archive.segmentFileName(recordingId, segmentBasePosition) and finds the file already on disk. Typical causes: re-recording onto a recordingId/directory that already contains segments, leftover segments from a crashed or aborted recording, or a misconfigured archiveDir pointing at a reused/non-empty directory with recordingId collisions.","commonSituations":"Restarting a recording after a crash without cleaning the archive dir; archiving into a shared or restored-from-backup directory where old segment files persist; replaying/recording fixtures that recreate the same recordingId and start position; mounting the same archiveDir for two archive processes.","solutions":["Delete or move the conflicting segment file from archiveDir, or choose a fresh archive directory for the new recording","If the old recording is unwanted, remove all files for that recordingId (segment files named <recordingId>-<position>.rec) so rollover targets are free","If the old recording must be kept, let the catalog assign a new recordingId instead of forcing/reusing one","Check for a second archive process or stale recording session writing to the same directory and stop it before resuming"],"exampleFix":"// before: blind reuse of a dirty archive dir\narchive-media-dir=/data/archive\n\n// after: assert a clean target or clean it before starting the archive/recording\nFiles.move(Paths.get(\"/data/archive\", recordingId + \"-*.rec\"), backupDir); // or delete if stale","handlingStrategy":"validation","validationCode":"File archiveDir = new File(cfg.archiveDir);\nfor (long recId : recordingIdsToCreate) {\n    File[] existing = archiveDir.listFiles((d, n) -> n.startsWith(recId + \"-\"));\n    if (existing != null && existing.length > 0) {\n        throw new IllegalStateException(\"stale segments for recordingId \" + recId);\n    }\n}","typeGuard":"static boolean segmentFileOccupied(File archiveDir, long recordingId, long position) {\n    return new File(archiveDir, Archive.segmentFileName(recordingId, position)).exists();\n}","tryCatchPattern":"try {\n    archive.startRecording(channel, streamId, sourceLocation);\n} catch (ArchiveException e) {\n    if (e.getMessage().contains(\"segment file already exists\")) {\n        cleanOrRotateArchiveDir(); // remove stale segments, then retry\n    } else { throw e; }\n}","preventionTips":["Never point a new archive at a directory previously used by another archive instance without cleaning or catalog reconciliation","Use one archive process per archiveDir; never share it across JVMs or hosts","After a crash, clean up or recover the catalog and segment files before restarting recordings with reused recordingIds","Back up recordings by copying the whole archiveDir + catalog, not partially, so no orphan segment files remain"],"tags":["archive","segment-file","file-conflict","io"],"backgroundTag":"file-already-exists","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"}