stride3d/stride · error · InvalidOperationException

Cannot register a service on a NullServiceProvider.

Error message

Cannot register a service on a NullServiceProvider.

What it means

NullServiceProvider is a placeholder IViewModelServiceProvider whose TryGet always returns null; it is meant for view models that need no services. Since it can never resolve services, registering one on it is meaningless, so RegisterService throws InvalidOperationException to reject the misuse explicitly.

Solutions

  1. Use a real ViewModelServiceProvider instead of NullServiceProvider when services are needed
  2. Register services during provider construction, not on NullServiceProvider
  3. Audit why a null provider was selected (default/fallback logic)
  4. Assert the provider type before calling RegisterService

Example fix

// before
IViewModelServiceProvider provider = NullServiceProvider.Instance;
provider.RegisterService(new MyService()); // throws
// after
IViewModelServiceProvider provider = new ViewModelServiceProvider(new MyService());
Defensive patterns

Strategy: type-guard

Validate before calling

if (provider is NullServiceProvider)
    throw new InvalidOperationException("Cannot register services on NullServiceProvider; use a real provider.");

Type guard

static bool SupportsRegistration(IViewModelServiceProvider p) => p is not NullServiceProvider;

Try / catch

try { provider.RegisterService(service); }
catch (InvalidOperationException ex) when (ex.Message.Contains("NullServiceProvider")) { /* swap in a real provider */ }

Prevention

When it happens

Trigger: Calling RegisterService on NullServiceProvider directly, or on a ViewModelProvider/ViewModelBase wired to the null provider while attempting to add a service at runtime.

Common situations: Code that builds view models with the null provider in tests and later tries to attach services; a config path that fell back to NullServiceProvider unexpectedly; forgetting to swap in a real provider before registration.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/817668f7465511c9. Report an issue: GitHub.

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation/ViewModels/NullServiceProvider.cs:24

/// <summary>
/// A service provider that is empty and immutable.
/// </summary>
internal sealed class NullServiceProvider : IViewModelServiceProvider
{
    // We provide an empty `add' and `remove' to avoid a warning about unused events that we have
    // to implement as they are part of the IViewModelServiceProvider definition.
    /// <inheritdoc/>
    public event EventHandler<ServiceRegistrationEventArgs>? ServiceRegistered { add { } remove { } }

    // We provide an empty `add' and `remove' to avoid a warning about unused events that we have
    // to implement as they are part of the IViewModelServiceProvider definition.
    /// <inheritdoc/>
    public event EventHandler<ServiceRegistrationEventArgs>? ServiceUnregistered { add { } remove { } }

    /// <inheritdoc/>
    public void RegisterService(object service)
    {
        throw new InvalidOperationException("Cannot register a service on a NullServiceProvider.");
    }

    /// <inheritdoc/>
    public void UnregisterService(object service)
    {
        throw new InvalidOperationException("Cannot unregister a service on a NullServiceProvider.");
    }

    /// <inheritdoc/>
    public object? TryGet(Type serviceType)
    {
        return null;
    }

    /// <inheritdoc/>
    public T? TryGet<T>() where T : class
    {
        return null;

View on GitHub (pinned to 96fad776d2)