stride3d/stride · error · InvalidOperationException
A Virtual File Provider with the root path
Error message
A Virtual File Provider with the root path "{provider.RootPath}" already exists. What it means
VirtualFileSystem.RegisterProvider maintains a static registry keyed by provider RootPath; only one provider may exist per root path. If a provider with a non-null RootPath is registered and another provider (or the same one twice) already occupies that key, the TryAdd fails and this InvalidOperationException is thrown.
Solutions
- Check providers with VirtualFileSystem.GetProvider(rootPath) before calling RegisterProvider, or skip registration if it returns non-null.
- Call VirtualFileSystem.UnregisterProvider(rootPath) for stale providers before re-registering.
- Remove duplicate initialization code paths so the provider is registered exactly once per process.
- Use a distinct RootPath for the new provider if both mounts are genuinely needed.
Example fix
// before
VirtualFileSystem.RegisterProvider(new DatabaseFileProvider(mount));
// after
if (VirtualFileSystem.GetProvider(mount) == null)
VirtualFileSystem.RegisterProvider(new DatabaseFileProvider(mount)); Defensive patterns
Strategy: validation
Validate before calling
if (VirtualFileSystem.GetProvider(provider.RootPath) == null)
VirtualFileSystem.RegisterProvider(provider); Try / catch
try { VirtualFileSystem.RegisterProvider(provider); }
catch (InvalidOperationException) { /* provider for this root already mounted — reuse it */ } Prevention
- Always call GetProvider first or register inside a static lazy singleton
- Pair every RegisterProvider with UnregisterProvider in test teardown
- Use unique, namespaced root paths per module
When it happens
Trigger: Calling VirtualFileSystem.RegisterProvider twice with providers having the same RootPath (e.g. mounting '/assets' twice), or registering a provider whose root path collides with a provider auto-registered during engine startup.
Common situations: Game/plugins initializing asset systems in both app code and a bootstrap that runs twice (e.g. constructor + static initializer); test suites creating providers per test without unregistering via UnregisterProvider; duplicate mount entries in config.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- path [ ] cannot be resolved to a provider.
- path [ ] doesn't contain a /
- A service of the same type has already been registered.
- An error occurred while adding an item to the node, see the…
- An error occurred while adding an item to the node, see the…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/e7a5d26580e36c6c.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.IO/VirtualFileSystem.cs:120
/// <value>The providers.</value>
public static IEnumerable<IVirtualFileProvider> Providers
{
get
{
return providers.Values;
}
}
/// <summary>
/// Registers the specified virtual file provider at the specified mount location.
/// </summary>
/// <param name="provider">The provider.</param>
public static void RegisterProvider(IVirtualFileProvider provider)
{
if (provider.RootPath != null)
{
if (!providers.TryAdd(provider.RootPath, provider))
throw new InvalidOperationException($"A Virtual File Provider with the root path \"{provider.RootPath}\" already exists.");
}
}
/// <summary>
/// Unregisters the specified virtual file provider.
/// </summary>
/// <param name="provider">The provider.</param>
/// <param name="dispose">Indicate that the provider should be disposed, if it inherits from IDisposable interface.</param>
public static void UnregisterProvider(IVirtualFileProvider provider, bool dispose = true)
{
var mountPoints = providers.Where(x => x.Value == provider).ToArray();
foreach (var mountPoint in mountPoints)
providers.Remove(mountPoint.Key);
}
/// <summary>
/// Mounts the specified path in the specified virtual file mount point.
/// </summary>View on GitHub (pinned to 96fad776d2)