{"record":{"id":"3cfcfc28d0aa4b7e","repo":"SonarSource/sonarqube","slug":"directory-s-is-a-file","errorCode":null,"errorMessage":"Directory '%s' is a file","messagePattern":"Directory '(.+?)' is a file","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"server/sonar-process/src/main/java/org/sonar/process/FileUtils2.java","lineNumber":119,"sourceCode":"  /**\n   * Deletes a directory recursively. Does not support symbolic link to directories.\n   *\n   * @param directory  directory to delete\n   * @throws IOException in case deletion is unsuccessful\n   */\n  public static void deleteDirectory(File directory) throws IOException {\n    requireNonNull(directory, DIRECTORY_CAN_NOT_BE_NULL);\n\n    if (!directory.exists()) {\n      return;\n    }\n\n    Path path = directory.toPath();\n    if (Files.isSymbolicLink(path)) {\n      throw new IOException(format(\"Directory '%s' is a symbolic link\", directory));\n    }\n    if (directory.isFile()) {\n      throw new IOException(format(\"Directory '%s' is a file\", directory));\n    }\n    deleteDirectoryImpl(path);\n  }\n\n  /**\n   * Size of file or directory, in bytes. In case of a directory,\n   * the size is the sum of the sizes of all files recursively traversed.\n   *\n   * This implementation is recommended over commons-io\n   * {@code FileUtils#sizeOf(File)} which suffers from slow usage of Java IO.\n   *\n   * @throws IOException if files can't be traversed or size attribute is not present\n   * @see BasicFileAttributes#size()\n   */\n  public static long sizeOf(Path path) throws IOException {\n    SizeVisitor visitor = new SizeVisitor();\n    Files.walkFileTree(path, visitor);\n    return visitor.size;","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-process/src/main/java/org/sonar/process/FileUtils2.java#L101-L137","documentation":"FileUtils2.deleteDirectory throws this IOException when the given File exists but is a regular file rather than a directory. The guard exists so callers get a clear message instead of a confusing failure from the recursive delete walk.","triggerScenarios":"Calling FileUtils2.deleteDirectory(new File(path)) where path points to a regular file, not a directory (and is not a symlink).","commonSituations":"Path built from config/env with wrong trailing component; a file replaced a directory between planning and execution; code assumes extension implies directory.","solutions":["Check File.isDirectory() before calling deleteDirectory and delete the file with File.delete() instead","Verify the path configured actually points to a directory","Delete the file manually and retry"],"exampleFix":"// before\nFileUtils2.deleteDirectory(target);\n// after\nif (target.isFile()) {\n  target.delete();\n} else {\n  FileUtils2.deleteDirectory(target);\n}","handlingStrategy":"validation","validationCode":"if (!new File(path).isDirectory()) { throw new IllegalArgumentException(path + \" is not a directory\"); }\nFileUtils2.deleteDirectory(new File(path));","typeGuard":null,"tryCatchPattern":"try { FileUtils2.deleteDirectory(dir); } catch (IOException e) { if (e.getMessage().contains(\"is a file\")) { /* handle file-vs-dir */ } else throw e; }","preventionTips":["Always check File.isDirectory() before directory operations","Validate configured paths at startup","Never assume a path's type from its name or extension"],"tags":["filesystem","io","directory"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}