{"record":{"id":"3fb17a4253b7d7ce","repo":"apache/hadoop","slug":"cannot-copy-srcpath-which-is-not-a-file-to-tar","errorCode":null,"errorMessage":"Cannot copy {srcPath}, which is not a file to {targetPath}","messagePattern":"Cannot copy (.+?), which is not a file to (.+?)","errorType":"exception","errorClass":"InvalidInputException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-distcp/src/main/java/org/apache/hadoop/tools/SimpleCopyListing.java","lineNumber":168,"sourceCode":"      targetExists = true;\n    } catch (FileNotFoundException ignored) {\n    }\n    targetPath = targetFS.makeQualified(targetPath);\n    final boolean targetIsReservedRaw =\n        Path.getPathWithoutSchemeAndAuthority(targetPath).toString().\n            startsWith(HDFS_RESERVED_RAW_DIRECTORY_NAME);\n\n    //If target is a file, then source has to be single file\n    if (targetIsFile) {\n      if (context.getSourcePaths().size() > 1) {\n        throw new InvalidInputException(\"Multiple source being copied to a file: \" +\n            targetPath);\n      }\n\n      Path srcPath = context.getSourcePaths().get(0);\n      FileSystem sourceFS = srcPath.getFileSystem(getConf());\n      if (!sourceFS.isFile(srcPath)) {\n        throw new InvalidInputException(\"Cannot copy \" + srcPath +\n            \", which is not a file to \" + targetPath);\n      }\n    }\n\n    if (context.shouldAtomicCommit() && targetExists) {\n      throw new InvalidInputException(\"Target path for atomic-commit already exists: \" +\n        targetPath + \". Cannot atomic-commit to pre-existing target-path.\");\n    }\n\n    for (Path path: context.getSourcePaths()) {\n      FileSystem fs = path.getFileSystem(getConf());\n      if (!fs.exists(path)) {\n        throw new InvalidInputException(path + \" doesn't exist\");\n      }\n      if (Path.getPathWithoutSchemeAndAuthority(path).toString().\n          startsWith(HDFS_RESERVED_RAW_DIRECTORY_NAME)) {\n        if (!targetIsReservedRaw) {\n          final String msg = \"The source path '\" + path + \"' starts with \" +","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-distcp/src/main/java/org/apache/hadoop/tools/SimpleCopyListing.java#L150-L186","documentation":"The target exists and is a file, there is exactly one source path, but sourceFS.isFile(srcPath) is false - the single source is a directory (or something that is not a regular file). File-to-file copy requires the source to be a file; directory-onto-file is rejected at listing time.","triggerScenarios":"hadoop distcp hdfs://a/somedir hdfs://b/existingFile; a source that is a symlink-to-directory or a mount point resolving as a directory; intending to copy one file but pointing at its parent directory.","commonSituations":"forgetting the filename portion of the source path; targets auto-created as files by earlier tools; globs that collapsed to a directory.","solutions":["If you meant dir-to-dir: delete or rename the file target, then copy onto a nonexistent or directory target.","If you meant file-to-file: point the source at the actual file, e.g. hdfs://a/somedir/file.ext.","Verify both endpoints: hadoop fs -ls on source and target to see which one has the wrong type."],"exampleFix":"# before: source is a directory, target is a file\nhadoop distcp hdfs://a/somedir hdfs://b/existing.bin\n\n# after: copy the file, or target a directory\nhadoop distcp hdfs://a/somedir/actual.bin hdfs://b/existing.bin","handlingStrategy":"validation","validationCode":"// Pre-flight: file-to-file copy requires the single source to be a file\nFileSystem tfs = targetPath.getFileSystem(conf);\nif (tfs.exists(targetPath) && tfs.getFileStatus(targetPath).isFile()\n    && context.getSourcePaths().size() == 1) {\n  Path src = context.getSourcePaths().get(0);\n  FileSystem sfs = src.getFileSystem(conf);\n  if (!sfs.isFile(src)) {\n    throw new InvalidInputException(\n        \"Source \" + src + \" is not a file but target \" + targetPath + \" is\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  copyListing.doBuildListing(listingFile, context);\n} catch (InvalidInputException e) {\n  if (e.getMessage().startsWith(\"Cannot copy\") && e.getMessage().contains(\"which is not a file\")) {\n    // point the source at the actual file, or make the target a directory\n    fixSourceOrTargetType(e.getMessage());\n  } else {\n    throw e;\n  }\n}","preventionTips":["Check hadoop fs -ls on both endpoints when copying onto an existing path.","Include the filename in the source path when the target is a file."],"tags":["distcp","target-path","file-target","input-validation"],"backgroundTag":"invalid-source-target-combination","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}