ppy/osu · error · ArgumentException
Destination provided is inside the source
Error message
Destination provided is inside the source
What it means
Thrown by MigratableStorage.Migrate when destinationUri is inside sourceUri (Uri.IsBaseOf). Moving the data store into one of its own subdirectories would create recursion and data corruption, so it is hard-rejected before CopyRecursive runs.
Source
Thrown at osu.Game/IO/MigratableStorage.cs:57
/// <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)
{
bool allFilesDeleted = true;
View on GitHub (pinned to d9c73e12ad)
Solutions
- Reject destinations that are base-relative to the source in the picker UI before calling Migrate.
- Choose a destination on a different volume or a sibling directory that is provably not under the source.
- If a nested layout is genuinely desired, copy out manually first then re-point storage, avoiding Migrate's guard.
Example fix
// before
storage.Migrate(new DesktopStorage(Path.Combine(currentRoot, "backup"), host)); // throws
// after
string dst = Path.GetFullPath(userChosenPath + Path.DirectorySeparatorChar);
string src = Path.GetFullPath(storage.GetFullPath(".") + Path.DirectorySeparatorChar);
if (new Uri(src).IsBaseOf(new Uri(dst)))
throw new InvalidOperationException("Cannot migrate into a subdirectory of the current storage.");
storage.Migrate(new DesktopStorage(userChosenPath, host)); Defensive patterns
Strategy: validation
Validate before calling
var srcUri = new Uri(Path.GetFullPath(storage.GetFullPath(".") + Path.DirectorySeparatorChar));
var dstUri = new Uri(Path.GetFullPath(newPath + Path.DirectorySeparatorChar));
if (srcUri.IsBaseOf(dstUri)) throw new InvalidOperationException("Destination is inside source."); Type guard
static bool IsDestinationInsideSource(string source, string dest)
=> new Uri(Path.GetFullPath(source) + Path.DirectorySeparatorChar)
.IsBaseOf(new Uri(Path.GetFullPath(dest) + Path.DirectorySeparatorChar)); Try / catch
try { storage.Migrate(target); }
catch (ArgumentException ex) when (ex.Message.Contains("inside the source"))
{ /* prompt user to choose a folder outside the current data dir */ } Prevention
- Filter the folder picker to exclude the current data root and its descendants.
- Prefer destinations on a different volume to avoid nesting entirely.
- Document that the data store cannot be moved into its own subdirectory.
When it happens
Trigger: Calling Migrate(newStorage) where the target path is a subdirectory of the current storage root — e.g. migrating osu!/ into osu!/backup/ . The IsBaseOf check catches nested locations.
Common situations: User selects a folder inside the current data directory as the new location; default migration path derived from the current path by appending a subfolder; nested install layouts.
Related errors
- Destination provided already has files or directories presen
- Destination provided is already the current location
- 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/e6e180144c3e8332.
Report an issue: GitHub.