{"record":{"id":"596d166bb13a5791","repo":"ppy/osu","slug":"destination-provided-is-already-the-current-locati","errorCode":null,"errorMessage":"Destination provided is already the current location","messagePattern":"Destination provided is already the current location","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"osu.Game/IO/MigratableStorage.cs","lineNumber":54,"sourceCode":"        {\r\n        }\r\n\r\n        /// <summary>\r\n        /// A general purpose migration method to move the storage to a different location.\r\n        /// <param name=\"newStorage\">The target storage of the migration.</param>\r\n        /// </summary>\r\n        /// <returns>Whether cleanup could complete.</returns>\r\n        public virtual bool Migrate(Storage newStorage)\r\n        {\r\n            var source = new DirectoryInfo(GetFullPath(\".\"));\r\n            var destination = new DirectoryInfo(newStorage.GetFullPath(\".\"));\r\n\r\n            // using Uri is the easiest way to check equality and contains (https://stackoverflow.com/a/7710620)\r\n            var sourceUri = new Uri(source.FullName + Path.DirectorySeparatorChar);\r\n            var destinationUri = new Uri(destination.FullName + Path.DirectorySeparatorChar);\r\n\r\n            if (sourceUri == destinationUri)\r\n                throw new ArgumentException(\"Destination provided is already the current location\", destination.FullName);\r\n\r\n            if (sourceUri.IsBaseOf(destinationUri))\r\n                throw new ArgumentException(\"Destination provided is inside the source\", destination.FullName);\r\n\r\n            // ensure the new location has no files present, else hard abort\r\n            if (destination.Exists)\r\n            {\r\n                if (destination.GetFiles().Length > 0 || destination.GetDirectories().Length > 0)\r\n                    throw new ArgumentException(\"Destination provided already has files or directories present\", destination.FullName);\r\n            }\r\n\r\n            CopyRecursive(source, destination);\r\n            ChangeTargetStorage(newStorage);\r\n\r\n            return DeleteRecursive(source);\r\n        }\r\n\r\n        protected bool DeleteRecursive(DirectoryInfo target, bool topLevelExcludes = true)\r","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/ppy/osu/blob/d9c73e12adff2feaae4a3e158d36fe5883faf6ca/osu.Game/IO/MigratableStorage.cs#L36-L72","documentation":"Thrown by MigratableStorage.Migrate when the source and destination directories resolve to the same URI (after appending a directory separator). It's an early guard to prevent a no-op or self-overwrite migration; the same check structure guards against nested and non-empty destinations.","triggerScenarios":"Calling Migrate(newStorage) where newStorage.GetFullPath(\".\") normalises to the same absolute path as the current storage root (e.g. the user picked the existing data folder as the migration target).","commonSituations":"A 'move data folder' UI where the user selects the current location; a config that defaults the destination to the source path; symlinks/shortcuts resolving to the same real path.","solutions":["Before calling Migrate, resolve and compare both paths with the same Uri normalisation the method uses; reject identical paths in the UI.","If the user intent is 'no change', treat equality as a successful no-op rather than erroring.","Resolve symlinks/junctions to real paths before comparison to catch aliases pointing at the source."],"exampleFix":"// before\nstorage.Migrate(new DesktopStorage(userChosenPath, host)); // throws if same\n\n// after\nstring src = Path.GetFullPath(storage.GetFullPath(\".\") + Path.DirectorySeparatorChar);\nstring dst = Path.GetFullPath(userChosenPath + Path.DirectorySeparatorChar);\nif (new Uri(src) == new Uri(dst))\n{\n    Logger.Log(\"Migration target is current location; nothing to do.\");\n    return true;\n}\nreturn storage.Migrate(new DesktopStorage(userChosenPath, host));","handlingStrategy":"validation","validationCode":"string src = Path.GetFullPath(storage.GetFullPath(\".\") + Path.DirectorySeparatorChar);\nstring dst = Path.GetFullPath(newPath + Path.DirectorySeparatorChar);\nif (new Uri(src) == new Uri(dst)) { /* no-op success */ return true; }","typeGuard":"static bool IsSameLocation(string a, string b)\n    => new Uri(Path.GetFullPath(a) + Path.DirectorySeparatorChar)\n       == new Uri(Path.GetFullPath(b) + Path.DirectorySeparatorChar);","tryCatchPattern":"try { storage.Migrate(target); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"already the current location\"))\n{ /* treat as success: nothing to migrate */ }","preventionTips":["Resolve both paths with the same Uri normalisation the method uses before offering migration.","In the picker, disable 'Migrate' when the chosen path equals the current data root.","Resolve symlinks/junctions to their real targets before comparing."],"tags":["filesystem","migration","storage","validation"],"backgroundTag":null,"analyzedSha":"d9c73e12adff2feaae4a3e158d36fe5883faf6ca","analyzedAt":"2026-08-13T14:12:54.015Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}