{"record":{"id":"f747a69af1144248","repo":"apache/hadoop","slug":"source-srcfile-exists-but-is-a-directory","errorCode":null,"errorMessage":"Source '{srcFile}' exists but is a directory","messagePattern":"Source '(.+?)' exists but is a directory","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/common/Storage.java","lineNumber":1336,"sourceCode":"   *  should be the same as the original\n   *\n   * @throws NullPointerException if source or destination is {@code null}\n   * @throws IOException if source or destination is invalid\n   * @throws IOException if an IO error occurs during copying\n   */\n  public static void nativeCopyFileUnbuffered(File srcFile, File destFile,\n      boolean preserveFileDate) throws IOException {\n    if (srcFile == null) {\n      throw new NullPointerException(\"Source must not be null\");\n    }\n    if (destFile == null) {\n      throw new NullPointerException(\"Destination must not be null\");\n    }\n    if (srcFile.exists() == false) {\n      throw new FileNotFoundException(\"Source '\" + srcFile + \"' does not exist\");\n    }\n    if (srcFile.isDirectory()) {\n      throw new IOException(\"Source '\" + srcFile + \"' exists but is a directory\");\n    }\n    if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {\n      throw new IOException(\"Source '\" + srcFile + \"' and destination '\" +\n          destFile + \"' are the same\");\n    }\n    File parentFile = destFile.getParentFile();\n    if (parentFile != null) {\n      if (!parentFile.mkdirs() && !parentFile.isDirectory()) {\n        throw new IOException(\"Destination '\" + parentFile\n            + \"' directory cannot be created\");\n      }\n    }\n    if (destFile.exists()) {\n      if (FileUtil.canWrite(destFile) == false) {\n        throw new IOException(\"Destination '\" + destFile\n            + \"' exists but is read-only\");\n      } else {\n        if (destFile.delete() == false) {","sourceCodeStart":1318,"sourceCodeEnd":1354,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/common/Storage.java#L1318-L1354","documentation":"Guard clause of Storage.nativeCopyFileUnbuffered: srcFile exists but isDirectory() is true. The helper copies a single regular file with OS unbuffered IO; directories are rejected so NativeIO.copyFileUnbuffered never receives a directory handle.","triggerScenarios":"The source path points at a directory (e.g. the checkpoint directory instead of the fsimage inside it); a glob or config value expanded to a directory; a path where the expected file was replaced by a same-named directory.","commonSituations":"Configuring a copy source with a directory-level setting instead of the file; tests with fixture layout mismatches; scripts that pass dirname instead of a file path.","solutions":["Point the copy at the file inside the directory","If a whole directory must be copied, walk its entries and copy each file (e.g. FileUtil.copy) rather than this single-file API"],"exampleFix":"// before\nStorage.nativeCopyFileUnbuffered(new File(\"/nn/current\"), dst, true);\n// after\nStorage.nativeCopyFileUnbuffered(new File(\"/nn/current/fsimage_0001\"), dst, true);","handlingStrategy":"validation","validationCode":"if (srcFile != null && srcFile.isDirectory()) {\n  throw new IOException(\"expected a file but got directory: \" + srcFile.getAbsolutePath());\n}","typeGuard":"static boolean isFileNotDirectory(File f) {\n  return f != null && f.isFile() && !f.isDirectory();\n}","tryCatchPattern":null,"preventionTips":["Use File.isFile() (not exists()) when validating copy sources","Keep directory-level and file-level config settings clearly named to avoid mix-ups"],"tags":["hdfs","file-copy","path-validation","filesystem"],"backgroundTag":"expected-file-found-directory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}