{"record":{"id":"f3c1f5ec507b17f4","repo":"apache/seatunnel","slug":"exceptionutils-getmessage-e","errorCode":null,"errorMessage":"${ExceptionUtils.getMessage(e)}","messagePattern":"\\$\\{ExceptionUtils\\.getMessage\\(e\\)\\}","errorType":"exception","errorClass":"CheckpointStorageException","httpStatus":null,"severity":"error","filePath":"seatunnel-engine/seatunnel-engine-storage/checkpoint-storage-plugins/checkpoint-storage-local-file/src/main/java/org/apache/seatunnel/engine/checkpoint/storage/localfile/LocalFileStorage.java","lineNumber":157,"sourceCode":"                    } catch (IOException e) {\n                        log.error(\n                                \"Failed to read checkpoint data from file \"\n                                        + file.getAbsolutePath(),\n                                e);\n                    }\n                });\n        return states;\n    }\n\n    @Override\n    public List<PipelineState> getLatestCheckpoint(String jobId) throws CheckpointStorageException {\n        String parentPath = getStorageParentDirectory() + jobId;\n        Collection<File> fileList = new ArrayList<>();\n        try {\n            fileList = FileUtils.listFiles(new File(parentPath), FILE_EXTENSIONS, false);\n        } catch (Exception e) {\n            if (!(e.getCause() instanceof NoSuchFileException)) {\n                throw new CheckpointStorageException(ExceptionUtils.getMessage(e));\n            }\n        }\n        if (fileList.isEmpty()) {\n            log.info(\"No checkpoint found for this  job, the job id is: \" + jobId);\n            return new ArrayList<>();\n        }\n        Map<String, File> fileMap =\n                fileList.stream()\n                        .collect(\n                                Collectors.toMap(\n                                        File::getName, Function.identity(), (v1, v2) -> v2));\n        Set<String> latestPipelines = getLatestPipelineNames(fileMap.keySet());\n        List<PipelineState> latestPipelineFiles = new ArrayList<>(latestPipelines.size());\n        latestPipelines.forEach(\n                fileName -> {\n                    File file = fileMap.get(fileName);\n                    try {\n                        byte[] data = FileUtils.readFileToByteArray(file);","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-engine/seatunnel-engine-storage/checkpoint-storage-plugins/checkpoint-storage-local-file/src/main/java/org/apache/seatunnel/engine/checkpoint/storage/localfile/LocalFileStorage.java#L139-L175","documentation":"LocalFileStorage.getLatestCheckpoint throws CheckpointStorageException with the flattened message of the underlying exception when listing checkpoint files in the job directory fails with anything other than a NoSuchFileException cause. A missing directory is tolerated (returns empty list), but genuine IO failures (permissions, disk errors) are surfaced. The message is the ExceptionUtils.getMessage of the original exception, so the root cause text is embedded.","triggerScenarios":"Calling getLatestCheckpoint(jobId) when FileUtils.listFiles on getStorageParentDirectory()+jobId throws an exception whose cause is not NoSuchFileException — e.g. read permission denied on the job directory, IO error during traversal, or the path exists but is not a readable directory.","commonSituations":"Checkpoint directory permissions restricted after job submission; storage volume became read-only or failed; checkpoint data cleaned up concurrently while another process holds a lock; path collision where jobId segment resolves to a regular file.","solutions":["Inspect the embedded cause message to identify the filesystem failure (permission, IO, etc.).","Fix directory permissions so the engine user can read the job's checkpoint directory.","Verify the storage parent directory config resolves to a valid mounted path.","If the directory may legitimately be absent, ensure cleanup logic deletes the whole directory (then a NoSuchFileException is tolerated and an empty list is returned)."],"exampleFix":"// before\nthrow new CheckpointStorageException(ExceptionUtils.getMessage(e));\n// after\nthrow new CheckpointStorageException(\n    \"Failed to list checkpoints for job \" + jobId + \": \" + ExceptionUtils.getMessage(e), e);","handlingStrategy":"try-catch","validationCode":"java.nio.file.Path dir = java.nio.file.Path.of(storageParentDir, jobId);\nif (java.nio.file.Files.exists(dir) && !(java.nio.file.Files.isDirectory(dir) && java.nio.file.Files.isReadable(dir))) {\n    throw new IllegalStateException(\"Checkpoint path exists but is not a readable directory: \" + dir);\n}","typeGuard":"static boolean listableDirectory(Path p) {\n    return !Files.exists(p) || (Files.isDirectory(p) && Files.isReadable(p));\n}","tryCatchPattern":"try {\n    latest = storage.getLatestCheckpoint(jobId);\n} catch (CheckpointStorageException e) {\n    log.error(\"Listing checkpoints failed for job {}: {}\", jobId, e.getMessage(), e);\n    latest = Collections.emptyList(); // or rethrow depending on recovery policy\n}","preventionTips":["Keep the storage volume readable and healthy; monitor disk/mount health.","Never replace the job directory with a file or symlink loop.","If the directory may be legitimately absent, delete the whole directory (missing dir is tolerated, listing errors are not).","Log the embedded cause message to distinguish permissions vs IO failures."],"tags":["checkpoint","local-file-storage","filesystem-io","recovery"],"backgroundTag":"file-read-failed","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}