{"record":{"id":"c3480503f875a48a","repo":"chinabugotech/hutool","slug":"dest-is-a-sub-directory-of-src","errorCode":null,"errorMessage":"Dest is a sub directory of src !","messagePattern":"Dest is a sub directory of src !","errorType":"exception","errorClass":"IORuntimeException","httpStatus":null,"severity":"error","filePath":"hutool-core/src/main/java/cn/hutool/core/io/file/FileCopier.java","lineNumber":188,"sourceCode":"\t\tfinal File src = this.src;\n\t\tFile dest = this.dest;\n\t\t// check\n\t\tAssert.notNull(src, \"Source File is null !\");\n\t\tif (false == src.exists()) {\n\t\t\tthrow new IORuntimeException(\"File not exist: \" + src);\n\t\t}\n\t\tAssert.notNull(dest, \"Destination File or directiory is null !\");\n\t\tif (FileUtil.equals(src, dest)) {\n\t\t\tthrow new IORuntimeException(\"Files '{}' and '{}' are equal\", src, dest);\n\t\t}\n\n\t\tif (src.isDirectory()) {// 复制目录\n\t\t\tif(dest.exists() && false == dest.isDirectory()) {\n\t\t\t\t//源为目录，目标为文件，抛出IO异常\n\t\t\t\tthrow new IORuntimeException(\"Src is a directory but dest is a file!\");\n\t\t\t}\n\t\t\tif(FileUtil.isSub(src, dest)) {\n\t\t\t\tthrow new IORuntimeException(\"Dest is a sub directory of src !\");\n\t\t\t}\n\n\t\t\tfinal File subTarget = isCopyContentIfDir ? dest : FileUtil.mkdir(FileUtil.file(dest, src.getName()));\n\t\t\tinternalCopyDirContent(src, subTarget);\n\t\t} else {// 复制文件\n\t\t\tdest = internalCopyFile(src, dest);\n\t\t}\n\t\treturn dest;\n\t}\n\n\t//----------------------------------------------------------------------------------------- Private method start\n\t/**\n\t * 拷贝目录内容，只用于内部，不做任何安全检查<br>\n\t * 拷贝内容的意思为源目录下的所有文件和目录拷贝到另一个目录下，而不拷贝源目录本身\n\t *\n\t * @param src 源目录\n\t * @param dest 目标目录\n\t * @throws IORuntimeException IO异常","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-core/src/main/java/cn/hutool/core/io/file/FileCopier.java#L170-L206","documentation":"FileCopier.copy() detects when dest is a subdirectory of src via FileUtil.isSub. Copying a directory into its own descendant would recurse infinitely (the copy keeps finding newly created children), so it throws IORuntimeException(\"Dest is a sub directory of src !\").","triggerScenarios":"Calling copy() on a FileCopier where dest is inside src — e.g. src=/a, dest=/a/b.","commonSituations":"Copying a folder into itself or one of its children; a backup-into-source mistake; dest computed as a subpath of src.","solutions":["Choose a dest that is outside the src directory tree.","Copy to a sibling or ancestor location first, then move if needed.","Check FileUtil.isSub(src, dest) before copy() and reject early."],"exampleFix":"// before\nFileCopier.create(new File(\"/a\"), new File(\"/a/b\")).copy(); // throws: sub dir\n\n// after: copy outside the tree, then relocate\nFile staging = new File(\"/tmp/staging_b\");\nFileCopier.create(new File(\"/a\"), staging).copy();\n// optionally move staging into /a after copy completes","handlingStrategy":"validation","validationCode":"if (src.isDirectory() && FileUtil.isSub(src, dest)) {\n    // dest is inside src: choose an outside target\n    throw new IllegalArgumentException(\"dest must not be inside src\");\n}\nreturn FileCopier.create(src, dest).copy();","typeGuard":"static boolean isSafeCopyTarget(File src, File dest) {\n    return !(src != null && src.isDirectory() && FileUtil.isSub(src, dest));\n}","tryCatchPattern":"try {\n    return FileCopier.create(src, dest).copy();\n} catch (IORuntimeException e) {\n    if (e.getMessage().contains(\"sub directory of src\")) {\n        // dest is inside src: copy to an outside staging dir first\n    }\n    throw e;\n}","preventionTips":["Never set dest to a path inside src when copying a directory.","Copy to a sibling or external staging location, then move if needed.","Check FileUtil.isSub(src, dest) before copying directories."],"tags":["io","file","copy","recursion-safety"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}