dotnet/aspnetcore · error · InvalidOperationException
The subscriber with the given section ID '{identifier}' is a
Error message
The subscriber with the given section ID '{identifier}' is already unsubscribed. What it means
Thrown by SectionRegistry.Unsubscribe when Dictionary.Remove returns false — i.e. the identifier was never a subscriber key, or was already removed. Unsubscribe is called from SectionOutlet.Dispose and from SectionOutlet.SetParametersAsync when the identifier changes; the throw indicates an unsubscribe without a matching subscribe.
Source
Thrown at src/Components/Components/src/Sections/SectionRegistry.cs:85
if (_subscribersByIdentifier.ContainsKey(identifier))
{
throw new InvalidOperationException($"There is already a subscriber to the content with the given section ID '{identifier}'.");
}
// Notify the new subscriber with any existing content.
var provider = GetCurrentProviderContentOrDefault(identifier);
subscriber.ContentUpdated(provider);
_subscribersByIdentifier.Add(identifier, subscriber);
DetectRenderModeMismatch(identifier, subscriber, provider);
}
public void Unsubscribe(object identifier)
{
if (!_subscribersByIdentifier.Remove(identifier))
{
throw new InvalidOperationException($"The subscriber with the given section ID '{identifier}' is already unsubscribed.");
}
// The section pair is no longer complete, so re-arm the mismatch diagnostic in case the outlet
// and content are later reconnected in mismatched render modes.
_mismatchLoggedIdentifiers?.Remove(identifier);
}
public void NotifyContentProviderChanged(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}'.");
}
// We only notify content changed for subscribers when the content of the
// most recently added provider changes.
if (providers.Count != 0 && providers[^1] == provider)
{View on GitHub (pinned to 3600ca084e)
Solutions
- Do not call Dispose on SectionOutlet instances yourself; let the renderer own the lifecycle.
- If you hold a reference and must dispose defensively, null-out _subscribedIdentifier tracking in your own wrapper so Dispose is not re-entrant.
- Reproduce with Blazor's diagnostic logging enabled (Microsoft.AspNetCore.Components at Debug) to see whether SetParametersAsync or a prior Dispose already ran for the same outlet.
- Check for custom IComponent implementations that wrap SectionOutlet and forward Dispose incorrectly.
Example fix
// before: manual double-dispose of an outlet-holding component
outletHolder.Dispose();
outletHolder.Dispose(); // SectionOutlet.Dispose fires twice -> [343]
// after: idempotent dispose in the holder
private bool _disposed;
public void Dispose() { if (_disposed) return; _disposed = true; _outlet?.Dispose(); } Defensive patterns
Strategy: validation
Validate before calling
// If you wrap a SectionOutlet, track your own disposed flag:
private int _disposed; // Interlocked
public void Dispose() {
if (Interlocked.Exchange(ref _disposed, 1) == 0) _outlet.Dispose();
} Prevention
- Do not Dispose SectionOutlet instances manually.
- Make any wrapper component's Dispose idempotent.
- If you reproduce the throw, enable Microsoft.AspNetCore.Components at Debug to see the lifecycle order.
When it happens
Trigger: SectionOutlet.Dispose runs twice, or SetParametersAsync tries to unsubscribe from _subscribedIdentifier that was never subscribed (e.g. Attach never completed, or Dispose already ran).
Common situations: Disposing a SectionOutlet more than once from user code; a SectionOutlet whose SetParametersAsync never succeeded (so _subscribedIdentifier is set but Subscribe threw) and whose Dispose then tries to Unsubscribe; renderer disposal ordering edge cases during prerendering teardown or hot reload.
Related errors
- There are no content providers with the given section ID '{i
- The provider was not found in the providers list of the give
- 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/a416f08828f82c4f.
Report an issue: GitHub.