ppy/osu · error · ArgumentException

Destination provided is already the current location

Error message

Destination provided is already the current location

What it means

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.

Source

Thrown at osu.Game/IO/MigratableStorage.cs:54

        {
        }

        /// <summary>
        /// A general purpose migration method to move the storage to a different location.
        /// <param name="newStorage">The target storage of the migration.</param>
        /// </summary>
        /// <returns>Whether cleanup could complete.</returns>
        public virtual bool Migrate(Storage newStorage)
        {
            var source = new DirectoryInfo(GetFullPath("."));
            var destination = new DirectoryInfo(newStorage.GetFullPath("."));

            // using Uri is the easiest way to check equality and contains (https://stackoverflow.com/a/7710620)
            var sourceUri = new Uri(source.FullName + Path.DirectorySeparatorChar);
            var destinationUri = new Uri(destination.FullName + Path.DirectorySeparatorChar);

            if (sourceUri == destinationUri)
                throw new ArgumentException("Destination provided is already the current location", destination.FullName);

            if (sourceUri.IsBaseOf(destinationUri))
                throw new ArgumentException("Destination provided is inside the source", destination.FullName);

            // ensure the new location has no files present, else hard abort
            if (destination.Exists)
            {
                if (destination.GetFiles().Length > 0 || destination.GetDirectories().Length > 0)
                    throw new ArgumentException("Destination provided already has files or directories present", destination.FullName);
            }

            CopyRecursive(source, destination);
            ChangeTargetStorage(newStorage);

            return DeleteRecursive(source);
        }

        protected bool DeleteRecursive(DirectoryInfo target, bool topLevelExcludes = true)

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Before calling Migrate, resolve and compare both paths with the same Uri normalisation the method uses; reject identical paths in the UI.
  2. If the user intent is 'no change', treat equality as a successful no-op rather than erroring.
  3. Resolve symlinks/junctions to real paths before comparison to catch aliases pointing at the source.

Example fix

// before
storage.Migrate(new DesktopStorage(userChosenPath, host)); // throws if same

// after
string src = Path.GetFullPath(storage.GetFullPath(".") + Path.DirectorySeparatorChar);
string dst = Path.GetFullPath(userChosenPath + Path.DirectorySeparatorChar);
if (new Uri(src) == new Uri(dst))
{
    Logger.Log("Migration target is current location; nothing to do.");
    return true;
}
return storage.Migrate(new DesktopStorage(userChosenPath, host));
Defensive patterns

Strategy: validation

Validate before calling

string src = Path.GetFullPath(storage.GetFullPath(".") + Path.DirectorySeparatorChar);
string dst = Path.GetFullPath(newPath + Path.DirectorySeparatorChar);
if (new Uri(src) == new Uri(dst)) { /* no-op success */ return true; }

Type guard

static bool IsSameLocation(string a, string b)
    => new Uri(Path.GetFullPath(a) + Path.DirectorySeparatorChar)
       == new Uri(Path.GetFullPath(b) + Path.DirectorySeparatorChar);

Try / catch

try { storage.Migrate(target); }
catch (ArgumentException ex) when (ex.Message.Contains("already the current location"))
{ /* treat as success: nothing to migrate */ }

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13). Data as JSON: /api/errors/596d166bb13a5791. Report an issue: GitHub.