aeron-io/aeron · error · ArchiveException
segment file already exists: " + file
Error message
segment file already exists: " + file
What it means
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.
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
Example fix
// before: blind reuse of a dirty archive dir
archive-media-dir=/data/archive
// after: assert a clean target or clean it before starting the archive/recording
Files.move(Paths.get("/data/archive", recordingId + "-*.rec"), backupDir); // or delete if stale Defensive patterns
Strategy: validation
Validate before calling
File archiveDir = new File(cfg.archiveDir);
for (long recId : recordingIdsToCreate) {
File[] existing = archiveDir.listFiles((d, n) -> n.startsWith(recId + "-"));
if (existing != null && existing.length > 0) {
throw new IllegalStateException("stale segments for recordingId " + recId);
}
} Type guard
static boolean segmentFileOccupied(File archiveDir, long recordingId, long position) {
return new File(archiveDir, Archive.segmentFileName(recordingId, position)).exists();
} Try / catch
try {
archive.startRecording(channel, streamId, sourceLocation);
} catch (ArchiveException e) {
if (e.getMessage().contains("segment file already exists")) {
cleanOrRotateArchiveDir(); // remove stale segments, then retry
} else { throw e; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- failed to read link file=" + linkFile
- failed to open recording segment file " + segmentFileName
- failed to read fragment header
- Aeron client instance must set…
- Aeron client must use a RethrowingErrorHandler
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/9d7a55a6c45e7f1d.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/RecordingWriter.java:243
}
catch (final IOException ex)
{
CloseHelper.close(recordingFile);
close();
LangUtil.rethrowUnchecked(ex);
}
}
private void onFileRollOver()
{
CloseHelper.close(recordingFileChannel);
segmentOffset = 0;
segmentBasePosition += segmentLength;
final File file = new File(archiveDir, Archive.segmentFileName(recordingId, segmentBasePosition));
if (file.exists())
{
throw new ArchiveException("segment file already exists: " + file);
}
openRecordingSegmentFile(file);
}
private void checkErrorType(final IOException ex, final int writeLength)
{
boolean isLowStorageSpace = false;
IOException suppressed = null;
try
{
isLowStorageSpace = StorageSpaceException.isStorageSpaceError(ex) ||
ctx.archiveFileStore().getUsableSpace() < writeLength;
}
catch (final IOException ex2)
{
suppressed = ex2;View on GitHub (pinned to 6d60124e15)