{"record":{"id":"a730c4edef57fd4c","repo":"alibaba/spring-cloud-alibaba","slug":"file-exists-but-is-a-directory","errorCode":null,"errorMessage":"File '{}' exists but is a directory","messagePattern":"File '(.+?)' exists but is a directory","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"spring-cloud-alibaba-starters/spring-cloud-alibaba-commons/src/main/java/com/alibaba/cloud/commons/io/FileUtils.java","lineNumber":57,"sourceCode":"\t * error messages than simply calling <code>new FileInputStream(file)</code>.\n\t * <p>\n\t * At the end of the method either the stream will be successfully opened, or an\n\t * exception will have been thrown.\n\t * <p>\n\t * An exception is thrown if the file does not exist. An exception is thrown if the\n\t * file object exists but is a directory. An exception is thrown if the file exists\n\t * but cannot be read.\n\t * @param file the file to open for input, must not be {@code null}\n\t * @return a new {@link java.io.FileInputStream} for the specified file\n\t * @throws java.io.FileNotFoundException if the file does not exist\n\t * @throws IOException if the file object is a directory\n\t * @throws IOException if the file cannot be read\n\t * @since 1.3\n\t */\n\tpublic static FileInputStream openInputStream(final File file) throws IOException {\n\t\tif (file.exists()) {\n\t\t\tif (file.isDirectory()) {\n\t\t\t\tthrow new IOException(\"File '\" + file + \"' exists but is a directory\");\n\t\t\t}\n\t\t\tif (!file.canRead()) {\n\t\t\t\tthrow new IOException(\"File '\" + file + \"' cannot be read\");\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthrow new FileNotFoundException(\"File '\" + file + \"' does not exist\");\n\t\t}\n\t\treturn new FileInputStream(file);\n\t}\n\n\t// -----------------------------------------------------------------------\n\t/**\n\t * Reads the contents of a file into a String. The file is always closed.\n\t * @param file the file to read, must not be {@code null}\n\t * @param encoding the encoding to use, {@code null} means platform default\n\t * @return the file contents, never {@code null}\n\t * @throws IOException in case of an I/O error","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/alibaba/spring-cloud-alibaba/blob/115d5901102009492e05d5ec18c3f79cad4077d0/spring-cloud-alibaba-starters/spring-cloud-alibaba-commons/src/main/java/com/alibaba/cloud/commons/io/FileUtils.java#L39-L75","documentation":"Thrown by FileUtils.openInputStream (a copy of Apache Commons IO) when the File object exists on the filesystem but is a directory rather than a regular file. The method performs three sequential checks: existence, directory, readability. This is the directory check — it fires after file.exists() returns true but before attempting to open the stream, preventing a misleading error from the underlying FileInputStream constructor.","triggerScenarios":"Calling FileUtils.openInputStream(file) (or readFileToString which delegates to it) where file points to an existing directory path. Common when a configured file path resolves to a folder, or when a path like '/data/configs' is a directory containing multiple files rather than a single file.","commonSituations":"1) A configuration property specifies a directory path instead of a file path (e.g., spring config location pointing to a folder). 2) A path is dynamically constructed and accidentally resolves to a parent directory. 3) A resource that was expected to be a file was created as a directory by a deployment script.","solutions":["Check that the path points to a file, not a directory: use file.isFile() before calling openInputStream.","If you intended to read all files in a directory, use file.listFiles() and iterate, calling openInputStream on each individual file.","Correct the configuration property or path variable to point to the specific file."],"exampleFix":"// before\nFileUtils.openInputStream(new File(\"/data/configs\")); // is a directory\n\n// after\nFileUtils.openInputStream(new File(\"/data/configs/application.yml\"));","handlingStrategy":"validation","validationCode":"import java.io.File;\n\nFile file = new File(path);\nif (file.isDirectory()) {\n    throw new IllegalArgumentException(\n        \"Path '\" + path + \"' is a directory, expected a file\");\n}\nFileInputStream fis = FileUtils.openInputStream(file);","typeGuard":"import java.io.File;\n\nboolean isReadableFile(File file) {\n    return file != null && file.exists() && file.isFile() && file.canRead();\n}\n\n// Usage:\nif (isReadableFile(file)) {\n    String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);\n}","tryCatchPattern":"try {\n    InputStream in = FileUtils.openInputStream(file);\n    // use stream\n} catch (IOException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"is a directory\")) {\n        log.error(\"Path is a directory, not a file: {}\", file);\n    }\n    throw e;\n}","preventionTips":["Always validate file.isFile() before passing to openInputStream.","Use Spring's Resource abstraction (ResourceUtils.getFile) which can distinguish files from directories.","Log the resolved absolute path in configuration validation to catch directory-as-file mistakes early."],"tags":["file-io","commons-io","validation","filesystem"],"backgroundTag":null,"analyzedSha":"115d5901102009492e05d5ec18c3f79cad4077d0","analyzedAt":"2026-08-14T04:47:13.900Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}