{"record":{"id":"cf7e243562b596fb","repo":"apache/hadoop","slug":"src-should-be-a-directory","errorCode":null,"errorMessage":"{src} should be a directory.","messagePattern":"(.+?) should be a directory\\.","errorType":"validation","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-federation-balance/src/main/java/org/apache/hadoop/tools/fedbalance/DistCpProcedure.java","lineNumber":185,"sourceCode":"      return false;\n    case FINAL_DISTCP:\n      finalDistCp();\n      return false;\n    case FINISH:\n      finish();\n      return true;\n    default:\n      throw new IOException(\"Unexpected stage=\" + stage);\n    }\n  }\n\n  /**\n   * Pre check of src and dst.\n   */\n  void preCheck() throws IOException {\n    FileStatus status = srcFs.getFileStatus(src);\n    if (!status.isDirectory()) {\n      throw new IOException(src + \" should be a directory.\");\n    }\n    if (dstFs.exists(dst)) {\n      throw new IOException(dst + \" already exists.\");\n    }\n    if (srcFs.exists(new Path(src, HdfsConstants.DOT_SNAPSHOT_DIR))) {\n      throw new IOException(src + \" shouldn't enable snapshot.\");\n    }\n    updateStage(Stage.INIT_DISTCP);\n  }\n\n  /**\n   * The initial distcp. Copying src to dst.\n   */\n  void initDistCp() throws IOException, RetryException {\n    RunningJobStatus job = getCurrentJob();\n    if (job != null) {\n      // the distcp has been submitted.\n      if (job.isComplete()) {","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-federation-balance/src/main/java/org/apache/hadoop/tools/fedbalance/DistCpProcedure.java#L167-L203","documentation":"FedBalance's DistCpProcedure.preCheck() validates the source before the balance procedure starts: fedbalance can only balance directories, because it recursively walks src, enables snapshots on it, and diff-copies it to dst. If srcFs.getFileStatus(src) exists but is not a directory, the job aborts immediately with this IOException. It is a precondition failure raised before any data is moved.","triggerScenarios":"Submitting a fedbalance job (hdfs fedbalance) whose -src argument resolves to a regular file rather than a directory: status.isDirectory() is false in preCheck(). Also a symlink whose target is a file, or a path string with a trailing slash that still resolves to a file.","commonSituations":"Balancing a single file instead of its parent directory; scripts parameterized with file paths from an upstream stage; -src copied from an 'hdfs dfs -ls' row where a file path was picked instead of the directory.","solutions":["Point -src at the directory that contains the data (e.g. the parent directory of the file you named).","Verify before submitting: 'hdfs dfs -test -d <src> && echo dir || echo not-a-dir'.","Re-check the exact -src string for typos; note this error means the path EXISTS but is a file (a wrong path normally gives NoSuchFileException instead)."],"exampleFix":"# before\nhdfs fedbalance -src hdfs://ns1/user/alice/part-00000 -dst hdfs://ns2/balance/alice\n\n# after\nhdfs fedbalance -src hdfs://ns1/user/alice -dst hdfs://ns2/balance/alice","handlingStrategy":"validation","validationCode":"Path src = new Path(\"hdfs://ns1/data\");\nFileSystem srcFs = src.getFileSystem(conf);\nFileStatus st = srcFs.getFileStatus(src);\nif (!st.isDirectory()) {\n  throw new IllegalArgumentException(src + \" is a file; pass its parent directory to fedbalance\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Wrap fedbalance submissions in a preflight: 'hdfs dfs -test -d <src>' must succeed.","Feed scripts with directory parameters, not file listings."],"tags":["fedbalance","federation-balance","precheck","path-validation","distcp"],"backgroundTag":"path-validation-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}