dotnet/aspnetcore · error · InvalidOperationException

There are no content providers with the given section ID '{i

Error message

There are no content providers with the given section ID '{identifier}'.

What it means

Thrown by Blazor's internal SectionRegistry.RemoveProvider when SectionContent.Dispose (or a SectionId change on SectionContent) tries to unregister a provider for a section identifier that has no entry in _providersByIdentifier. It signals an unbalanced AddProvider/RemoveProvider pairing in the component lifecycle. The registry is keyed by the SectionName/SectionId object, so a missing key means that identifier was never registered, or was already removed.

Source

Thrown at src/Components/Components/src/Sections/SectionRegistry.cs:39

            providers = new();
            _providersByIdentifier.Add(identifier, providers);
        }

        if (isDefaultProvider)
        {
            providers.Insert(0, provider);
        }
        else
        {
            providers.Add(provider);
        }
    }

    public void RemoveProvider(object identifier, SectionContent provider)
    {
        if (!_providersByIdentifier.TryGetValue(identifier, out var providers))
        {
            throw new InvalidOperationException($"There are no content providers with the given section ID '{identifier}'.");
        }

        var index = providers.LastIndexOf(provider);

        if (index < 0)
        {
            throw new InvalidOperationException($"The provider was not found in the providers list of the given section ID '{identifier}'.");
        }

        providers.RemoveAt(index);

        if (index == providers.Count)
        {
            // We just removed the most recently added provider, meaning we need to change
            // the current content to that of second most recently added provider.
            var contentProvider = GetCurrentProviderContentOrDefault(providers);
            NotifyContentChangedForSubscriber(identifier, contentProvider);

View on GitHub (pinned to 3600ca084e)

Solutions

  1. Confirm SectionContent is rendered through the standard Blazor component lifecycle (not instantiated/disposed manually) so AddProvider always precedes RemoveProvider.
  2. Make sure Dispose is idempotent in your own code — do not call Dispose on the same SectionContent from two paths (e.g. a using block plus an explicit Dispose).
  3. Avoid mutating SectionName/SectionId from a non-UI thread; route identifier changes through ComponentState so SetParametersAsync runs the Add→Remove pair atomically.
  4. If you have a custom SectionContent subclass or a host that calls into the registry directly, audit every AddProvider/RemoveProvider call site to ensure they are symmetric per identifier.

Example fix

// before: double dispose path
_sectionA?.Dispose();
_sectionA?.Dispose(); // second call throws [340]

// after: guard the dispose
if (_sectionA is { } s && Interlocked.Exchange(ref _sectionA, null) is not null) s.Dispose();
Defensive patterns

Strategy: validation

Validate before calling

// Before rendering, assert each SectionContent's identifier was AddProvider'd
// by routing all SectionContent usage through the standard component lifecycle.
// In tests, walk the render tree and confirm every SectionContent has a non-null
// SectionName or SectionId and that the registry has a matching provider list:
// foreach (var (id, list) in registryProviders) Console.WriteLine($"{id}: {list.Count}");

Type guard

// C#: SectionContent is sealed; you cannot subclass. The actionable guard is on identifiers.
static bool IsValidSectionIdentifier(object? id) => id is string { Length: > 0 } s || (id is not null && !id.Equals(string.Empty));

Prevention

When it happens

Trigger: SectionContent.SetParametersAsync calls _registry.RemoveProvider(_registeredIdentifier, this) when the identifier changed, or SectionContent.Dispose calls it on teardown. The throw fires only when _providersByIdentifier has no list for that identifier — i.e. RemoveProvider was invoked without a preceding AddProvider, or the same identifier was already removed (double-dispose).

Common situations: Disposing a SectionContent instance whose AddProvider never ran (e.g. SetParametersAsync threw before line 78), calling Dispose twice on the same SectionContent, mutating SectionId from a background thread while a render is mid-flight, or a custom host that drives SectionContent outside the normal component lifecycle.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/7cd84191a2d872dc. Report an issue: GitHub.