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
- 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.
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
- 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.
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
- Destination provided is inside the source
- Destination provided already has files or directories presen
- Filename ""{filename}"" is not allowed.
- Attempting to block for migration took too long.
- Provided client ID must be an integer.
AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13).
Data as JSON: /api/errors/596d166bb13a5791.
Report an issue: GitHub.