{"record":{"id":"bffaf1c89c013256","repo":"apache/hadoop","slug":"can-t-replace-target-target-is-targettype-so","errorCode":null,"errorMessage":"Can't replace {target}. Target is {targetType}, Source is {sourceType}","messagePattern":"Can't replace (.+?)\\. Target is (.+?), Source is (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-distcp/src/main/java/org/apache/hadoop/tools/mapred/CopyMapper.java","lineNumber":203,"sourceCode":"            preserveXAttrs, preserveRawXattrs,\n            sourceFileStatus.getChunkOffset(),\n            sourceFileStatus.getChunkLength());\n      } catch (FileNotFoundException e) {\n        throw new IOException(new RetriableFileCopyCommand.CopyReadException(e));\n      }\n\n      FileStatus targetStatus = null;\n\n      try {\n        targetStatus = targetFS.getFileStatus(target);\n      } catch (FileNotFoundException ignore) {\n        if (LOG.isDebugEnabled())\n          LOG.debug(\"Path could not be found: \" + target, ignore);\n      }\n\n      if (targetStatus != null &&\n          (targetStatus.isDirectory() != sourceCurrStatus.isDirectory())) {\n        throw new IOException(\"Can't replace \" + target + \". Target is \" +\n            getFileType(targetStatus) + \", Source is \" + getFileType(sourceCurrStatus));\n      }\n\n      if (sourceCurrStatus.isDirectory()) {\n        createTargetDirsWithRetry(description, target, context, sourceStatus,\n            sourceFS);\n        return;\n      }\n\n      FileAction action = checkUpdate(sourceFS, sourceCurrStatus, target,\n          targetStatus);\n\n      Path tmpTarget = target;\n      if (action == FileAction.SKIP) {\n        LOG.info(\"Skipping copy of \" + sourceCurrStatus.getPath()\n                 + \" to \" + target);\n        updateSkipCounters(context, sourceCurrStatus);\n        context.write(null, new Text(\"SKIP: \" + sourceCurrStatus.getPath()));","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-distcp/src/main/java/org/apache/hadoop/tools/mapred/CopyMapper.java#L185-L221","documentation":"CopyMapper.statu­­s-checks each target path before copying: it fetches targetFS.getFileStatus(target), and if the target exists while its type (directory vs file) differs from the source's isDirectory(), distcp refuses to replace a file with a directory or vice versa. The guard fires before any data is written, so nothing on the target is modified.","triggerScenarios":"The source path is a directory but a regular file exists at the corresponding target path (or the reverse). Typical causes: the target tree was previously populated with a different layout, a leftover file sits where a directory is expected, or the destination is reused across dissimilar sources.","commonSituations":"Reusing one destination directory for different source layouts; a partially populated target from an earlier tool; copying /src/a (directory) onto /dst/a where 'a' is a file from a prior flat copy; upstream processes replacing directories with files.","solutions":["Identify the conflicting path from the message and remove or rename the mismatched entry on the target (hdfs dfs -rm / -mv)","Clean or change the destination so source and target layouts agree, then re-run with -update","Note that -overwrite does NOT bypass this check; the conflicting entry must be removed explicitly","Add a pre-flight scan comparing source/target types when reusing destinations"],"exampleFix":"# before: /dst/a is a FILE but /src/a is a DIRECTORY -> CopyMapper refuses\nhadoop distcp -update hdfs://nn/src/a hdfs://nn/dst/a\n\n# after: clear the conflicting entry, then re-run\nhdfs dfs -rm hdfs://nn/dst/a\nhadoop distcp -update hdfs://nn/src/a hdfs://nn/dst/a","handlingStrategy":"validation","validationCode":"// pre-flight: reject the copy if source/target types conflict\nfor (CopyListingFileStatus s : sourceList) {\n  Path target = new Path(targetRoot, relativize(targetRoot, s.getPath()));\n  if (targetFS.exists(target)\n      && targetFS.getFileStatus(target).isDirectory() != s.isDirectory()) {\n    // remove the conflicting entry or exclude this path from the listing\n  }\n}","typeGuard":null,"tryCatchPattern":"catch (IOException e) {  // wraps 'Can't replace <target>. Target is X, Source is Y'\n  // parse the target path from the message; delete/rename it and re-run with -update\n}","preventionTips":["When reusing destinations, pre-scan for name collisions between files and directories","Use one destination layout per source layout; avoid mixing flat and nested copies","Remember -overwrite never bypasses the file-vs-directory check","Clean stale files from target trees before large -update runs"],"tags":["distcp","hadoop","path-conflict","type-mismatch","filesystem"],"backgroundTag":"path-type-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}