{"record":{"id":"add3b74225669971","repo":"aeron-io/aeron","slug":"uncheckedioexception-while-backing-up-recording-log","errorCode":null,"errorMessage":"UncheckedIOException while backing up recording log","messagePattern":"UncheckedIOException while backing up recording log","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ClusterToolOperator.java","lineNumber":230,"sourceCode":"                {\n                    snapshotIndex = i;\n                    break;\n                }\n            }\n        }\n\n        final Path recordingLogBackup = clusterDir.toPath().resolve(RecordingLog.RECORDING_LOG_FILE_NAME + \".bak\");\n        try\n        {\n            Files.copy(\n                clusterDir.toPath().resolve(RecordingLog.RECORDING_LOG_FILE_NAME),\n                recordingLogBackup,\n                REPLACE_EXISTING,\n                COPY_ATTRIBUTES);\n        }\n        catch (final IOException ex)\n        {\n            throw new UncheckedIOException(ex);\n        }\n\n        if (Aeron.NULL_VALUE == snapshotIndex)\n        {\n            updateRecordingLog(clusterDir, Collections.emptyList());\n        }\n        else\n        {\n            final List<RecordingLog.Entry> truncatedEntries = new ArrayList<>();\n            int serviceId = ConsensusModule.Configuration.SERVICE_ID;\n            for (int i = snapshotIndex; i >= 0; i--)\n            {\n                final RecordingLog.Entry entry = entries.get(i);\n                if (RecordingLog.isValidSnapshot(entry) && entry.serviceId == serviceId)\n                {\n                    truncatedEntries.add(new RecordingLog.Entry(\n                        entry.recordingId,\n                        entry.leadershipTermId,","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ClusterToolOperator.java#L212-L248","documentation":"During seedRecordingLogFromSnapshot, ClusterToolOperator copies a snapshot into the recording log backup and, if an IOException occurs while backing up the recording log, wraps it in an UncheckedIOException with this message. It signals filesystem-level failure while seeding the recording log from a snapshot.","triggerScenarios":"Running a ClusterTool operation (e.g. recover/snapshot seeding) where the code attempts to copy files to recordingLogBackup with REPLACE_EXISTING/COPY_ATTRIBUTES and the underlying file operations raise IOException (missing source, bad permissions, full disk).","commonSituations":"Cluster directory on a read-only or full filesystem; the recording log backup file locked by another process; running the tool as a user without write permission to the cluster directory; corrupted cluster dir missing expected files.","solutions":["Check disk space and that the cluster directory is writable by the user running the tool.","Verify the source recording log / snapshot files exist and are readable.","Close other processes holding locks on the cluster directory (other cluster nodes, backup jobs).","Catch the UncheckedIOException and inspect the wrapped IOException's cause for the specific OS error."],"exampleFix":"// before\ntry (Stream<Path> ignored = Files.list(clusterDir)) { tool.seedRecordingLogFromSnapshot(...); } // fails with UncheckedIOException\n// after\ntry\n{\n    tool.seedRecordingLogFromSnapshot(...);\n}\ncatch (UncheckedIOException ex)\n{\n    System.err.println(\"backup failed: \" + ex.getCause()); // inspect underlying IOException\n}","handlingStrategy":"try-catch","validationCode":"// before running the tool\nPath clusterDir = Paths.get(clusterDirArg);\nif (!Files.isDirectory(clusterDir) || !Files.isWritable(clusterDir)) {\n    throw new IllegalStateException(\"cluster dir missing or not writable: \" + clusterDir);\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    operator.seedRecordingLogFromSnapshot(clusterDir, ...);\n}\ncatch (UncheckedIOException ex)\n{\n    IOException cause = ex.getCause();\n    // log cause, fix permissions/disk, retry\n}","preventionTips":["Run cluster tools as the same user that owns the cluster directory.","Monitor free disk space on the cluster volume.","Do not run tools concurrently with a live node."],"tags":["aeron","cluster","io","filesystem"],"backgroundTag":"file-write-failed","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}