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
- Confirm SectionContent is rendered through the standard Blazor component lifecycle (not instantiated/disposed manually) so AddProvider always precedes RemoveProvider.
- 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).
- Avoid mutating SectionName/SectionId from a non-UI thread; route identifier changes through ComponentState so SetParametersAsync runs the Add→Remove pair atomically.
- 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
- Never call SectionRegistry methods directly from app code; rely on SectionContent/SectionOutlet.
- Treat SectionContent.Dispose as renderer-owned — do not double-dispose.
- Keep SectionId/SectionName immutable after first render, or use @key to force clean re-instantiation on change.
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
- The provider was not found in the providers list of the give
- The subscriber with the given section ID '{identifier}' is a
- There is already a subscriber to the content with the given
- Services cannot be accessed before the component is initiali
- There is no file with ID ${fileId}. The file list may have c
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/7cd84191a2d872dc.
Report an issue: GitHub.