{"record":{"id":"60103b556cecc42d","repo":"apache/hadoop","slug":"is-a-directory-60103b","errorCode":null,"errorMessage":"Is a directory","messagePattern":"Is a directory","errorType":"exception","errorClass":"PathIsDirectoryException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/CommandWithDestination.java","lineNumber":295,"sourceCode":"  protected void processPath(PathData src) throws IOException {\n    processPath(src, getTargetPath(src));\n  }\n  \n  /**\n   * Called with a source and target destination pair\n   * @param src for the operation\n   * @param dst for the operation\n   * @throws IOException if anything goes wrong\n   */\n  protected void processPath(PathData src, PathData dst) throws IOException {\n    if (src.stat.isSymlink()) {\n      // TODO: remove when FileContext is supported, this needs to either\n      // copy the symlink or deref the symlink\n      throw new PathOperationException(src.toString());        \n    } else if (src.stat.isFile()) {\n      copyFileToTarget(src, dst);\n    } else if (src.stat.isDirectory() && !isRecursive()) {\n      throw new PathIsDirectoryException(src.toString());\n    }\n  }\n\n  @Override\n  protected void recursePath(PathData src) throws IOException {\n    PathData savedDst = dst;\n    try {\n      // modify dst as we descend to append the basename of the\n      // current directory being processed\n      dst = getTargetPath(src);\n      final boolean preserveRawXattrs =\n          checkPathsForReservedRaw(src.path, dst.path);\n      if (dst.exists) {\n        if (!dst.stat.isDirectory()) {\n          throw new PathIsNotDirectoryException(dst.toString());\n        }\n      } else {\n        if (!dst.fs.mkdirs(dst.path)) {","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/CommandWithDestination.java#L277-L313","documentation":"Thrown by CommandWithDestination.processPath(src, dst) when the source is a directory and the command was not run recursively (isRecursive() false). Copying a directory non-recursively has no defined output, so PathIsDirectoryException aborts with 'src: Is a directory'. Note most modern copy commands (put, get, cp in current releases) set setRecursive(true) internally, so this typically surfaces from commands or subclasses that leave recursion off (e.g. getmerge sources, custom commands extending CommandWithDestination).","triggerScenarios":"A source argument that expands to a directory while isRecursive() is false; passing a directory to a command whose USAGE only accepts files; a glob matching a directory among file results.","commonSituations":"Assuming every -cp variant needs no -r (older documentation); custom FsShell plugins built on CommandWithDestination that forget setRecursive(true); directory accidentally matched by a loose glob.","solutions":["Use the recursive form of the command where available (e.g. 'hdfs dfs -cp -r' style flows) so directories recurse","Point the command at the files inside the directory instead of the directory itself","If writing a CommandWithDestination subclass, call setRecursive(true) in processOptions when directory sources are legal"],"exampleFix":"# before (command with recursion off, source is a dir)\nhdfs dfs -cp /user/me/somedir /backup\n# after\nhdfs dfs -cp -r /user/me/somedir /backup  # current cp sets recursive internally; older/custom commands need it","handlingStrategy":"validation","validationCode":"// if recursion is not enabled, ensure every source is a regular file\nfor (Path s : sources) {\n  FileStatus st = fs.getFileStatus(s);\n  if (st.isDirectory()) {\n    throw new IOException(\"source is a directory but recursion is off: \" + s);\n  }\n}","typeGuard":"static boolean allSourcesAreFiles(FileSystem fs, List<Path> srcs) throws IOException {\n  for (Path p : srcs) if (fs.getFileStatus(p).isDirectory()) return false;\n  return true;\n}","tryCatchPattern":"try {\n  shellRun(copyCmd, src, dst);\n} catch (PathIsDirectoryException e) {\n  // e.getPath() is the directory source; retry in recursive mode\n  shellRun(copyCmd, \"-r\", e.getPath().toString(), dst);\n}","preventionTips":["Default to recursive flags (-r / commands that set setRecursive(true)) when sources may be trees","Validate source FileStatus types before dispatching to file-only commands","For custom CommandWithDestination subclasses, call setRecursive(true) if directories are legal input"],"tags":["hadoop","hdfs","is-a-directory","recursion","copy","shell"],"backgroundTag":"source-is-a-directory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}