{"record":{"id":"a416f08828f82c4f","repo":"dotnet/aspnetcore","slug":"the-subscriber-with-the-given-section-id-identif","errorCode":null,"errorMessage":"The subscriber with the given section ID '{identifier}' is already unsubscribed.","messagePattern":"The subscriber with the given section ID '(.+?)' is already unsubscribed\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/Sections/SectionRegistry.cs","lineNumber":85,"sourceCode":"        if (_subscribersByIdentifier.ContainsKey(identifier))\n        {\n            throw new InvalidOperationException($\"There is already a subscriber to the content with the given section ID '{identifier}'.\");\n        }\n\n        // Notify the new subscriber with any existing content.\n        var provider = GetCurrentProviderContentOrDefault(identifier);\n        subscriber.ContentUpdated(provider);\n\n        _subscribersByIdentifier.Add(identifier, subscriber);\n\n        DetectRenderModeMismatch(identifier, subscriber, provider);\n    }\n\n    public void Unsubscribe(object identifier)\n    {\n        if (!_subscribersByIdentifier.Remove(identifier))\n        {\n            throw new InvalidOperationException($\"The subscriber with the given section ID '{identifier}' is already unsubscribed.\");\n        }\n\n        // The section pair is no longer complete, so re-arm the mismatch diagnostic in case the outlet\n        // and content are later reconnected in mismatched render modes.\n        _mismatchLoggedIdentifiers?.Remove(identifier);\n    }\n\n    public void NotifyContentProviderChanged(object identifier, SectionContent provider)\n    {\n        if (!_providersByIdentifier.TryGetValue(identifier, out var providers))\n        {\n            throw new InvalidOperationException($\"There are no content providers with the given section ID '{identifier}'.\");\n        }\n\n        // We only notify content changed for subscribers when the content of the\n        // most recently added provider changes.\n        if (providers.Count != 0 && providers[^1] == provider)\n        {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Components/src/Sections/SectionRegistry.cs#L67-L103","documentation":"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.","triggerScenarios":"SectionOutlet.Dispose runs twice, or SetParametersAsync tries to unsubscribe from _subscribedIdentifier that was never subscribed (e.g. Attach never completed, or Dispose already ran).","commonSituations":"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.","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."],"exampleFix":"// before: manual double-dispose of an outlet-holding component\noutletHolder.Dispose();\noutletHolder.Dispose(); // SectionOutlet.Dispose fires twice -> [343]\n\n// after: idempotent dispose in the holder\nprivate bool _disposed;\npublic void Dispose() { if (_disposed) return; _disposed = true; _outlet?.Dispose(); }","handlingStrategy":"validation","validationCode":"// If you wrap a SectionOutlet, track your own disposed flag:\nprivate int _disposed; // Interlocked\npublic void Dispose() {\n    if (Interlocked.Exchange(ref _disposed, 1) == 0) _outlet.Dispose();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["blazor","components","sections","lifecycle","invalidoperation"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}