{"record":{"id":"b9931580fa9aa605","repo":"AlistGo/alist","slug":"same-name-files-cannot-be-moved","errorCode":null,"errorMessage":"same-name files cannot be moved","messagePattern":"same-name files cannot be moved","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/alias/driver.go","lineNumber":150,"sourceCode":"\t\treturn errs.PermissionDenied\n\t}\n\treqPath, err := d.getReqPath(ctx, parentDir, true)\n\tif err == nil {\n\t\treturn fs.MakeDir(ctx, stdpath.Join(*reqPath, dirName))\n\t}\n\tif errs.IsNotImplement(err) {\n\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}","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/alias/driver.go#L132-L168","documentation":"Returned by Alias.Move when getReqPath for the source object fails with errs.NotImplement: with ProtectSameName enabled, the source path exists in multiple underlying destinations sharing one alias key, so the driver cannot determine which physical file to move.","triggerScenarios":"ProtectSameName=true, the same alias key mapped to 2+ destinations, the source file present in more than one of them, and a Move(srcObj, dstDir) call through the alias mount.","commonSituations":"Merged mirror mounts (same content mirrored to two storages) with protect-mode on; users try to reorganize files via the alias entry and hit the ambiguity guard on the file being moved.","solutions":["Use unique alias keys per destination instead of one key over many paths","Move the file via the underlying storage mount directly","Disable ProtectSameName if writing to the first matching backend is acceptable","Delete the duplicate copy in one destination so the source resolves uniquely"],"exampleFix":"// before — ambiguous through alias\nfs.Move(ctx, \"/alias/data/file.txt\", \"/alias/target\")\n\n// after — address the concrete backend\nfs.Move(ctx, \"/netdisk_a/docs/file.txt\", \"/netdisk_a/target\")","handlingStrategy":"validation","validationCode":"// Ensure the source path resolves in exactly one destination before moving\nif len(d.pathMap[rootOf(srcPath)]) > 1 && d.ProtectSameName {\n    return errors.New(\"source is mirrored across destinations; move via a concrete mount\")\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    // retry against each concrete backend explicitly\n} else if err != nil { return err }","preventionTips":["Use unique alias keys per destination for any mount you move files through","Perform move operations on underlying mounts, not merged aliases","Keep mirrors in sync externally rather than relying on alias writes"],"tags":["alias","protect-same-name","move","ambiguous-target"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}