{"record":{"id":"ecfbe9946a95321b","repo":"AlistGo/alist","slug":"same-name-dirs-cannot-be-moved-to","errorCode":null,"errorMessage":"same-name dirs cannot be moved to","messagePattern":"same-name dirs cannot be moved to","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/alias/driver.go","lineNumber":157,"sourceCode":"\t\treturn errors.New(\"same-name dirs cannot make sub-dir\")\n\t}\n\treturn err\n}\n\nfunc (d *Alias) Move(ctx context.Context, srcObj, dstDir model.Obj) error {\n\tif !d.Writable {\n\t\treturn errs.PermissionDenied\n\t}\n\tsrcPath, err := d.getReqPath(ctx, srcObj, false)\n\tif errs.IsNotImplement(err) {\n\t\treturn errors.New(\"same-name files cannot be moved\")\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\tdstPath, err := d.getReqPath(ctx, dstDir, true)\n\tif errs.IsNotImplement(err) {\n\t\treturn errors.New(\"same-name dirs cannot be moved to\")\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn fs.Move(ctx, *srcPath, *dstPath)\n}\n\nfunc (d *Alias) Rename(ctx context.Context, srcObj model.Obj, newName string) error {\n\tif !d.Writable {\n\t\treturn errs.PermissionDenied\n\t}\n\treqPath, err := d.getReqPath(ctx, srcObj, false)\n\tif err == nil {\n\t\treturn fs.Rename(ctx, *reqPath, newName)\n\t}\n\tif errs.IsNotImplement(err) {\n\t\treturn errors.New(\"same-name files cannot be Rename\")\n\t}","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/alias/driver.go#L139-L175","documentation":"Returned by Alias.Move when the DESTINATION directory cannot be uniquely resolved: getReqPath on dstDir fails with errs.NotImplement because ProtectSameName is on and the destination folder exists in multiple destinations mapped under the same alias key. The move source was resolvable; the target was not.","triggerScenarios":"ProtectSameName=true; dstDir's alias key maps to multiple Paths entries; the destination folder exists in two or more of those underlying locations; Move is called with that dir as target.","commonSituations":"Moving files into a merged 'inbox' alias backed by two storages where the inbox folder already exists in both; mirrors kept in sync so both copies always exist, making every write into them ambiguous.","solutions":["Target a concrete destination by using a uniquely-keyed alias or the underlying mount path","Disable ProtectSameName to let the first resolved destination win (risky for mirrored data)","Keep merged mounts read-only (Writable=false) and write only through single-destination mounts","Remove the duplicate destination folder so only one candidate resolves"],"exampleFix":"# before — 'inbox' maps to two storages, both contain /\ninbox: /netdisk_a/inbox\ninbox: /netdisk_b/inbox\n\n# after — write path is unique\ninbox_a: /netdisk_a/inbox\ninbox_b: /netdisk_b/inbox","handlingStrategy":"validation","validationCode":"// Verify the destination resolves uniquely before the move\nif len(d.pathMap[rootOf(dstPath)]) > 1 && d.ProtectSameName {\n    return errors.New(\"destination mirrored; pick a single-backend target\")\n}","typeGuard":"// Go\nfunc isSameNameErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"same-name\")\n}","tryCatchPattern":"if err := d.Move(ctx, src, dst); isSameNameErr(err) {\n    // re-target a unique key or concrete mount, then retry once\n} else if err != nil { return err }","preventionTips":["Design write destinations as single-backend mounts","Avoid creating the same folder on every mirror if you also write through the alias","Prefer distinct keys (data_a, data_b) over one merged key for writable trees"],"tags":["alias","protect-same-name","move","destination"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}