{"record":{"id":"91df9af91f39a2aa","repo":"dotnet/wpf","slug":"sr-texteditorspellerinterophasbeendisposed-91df9a","errorCode":null,"errorMessage":"SR.TextEditorSpellerInteropHasBeenDisposed","messagePattern":"SR\\.TextEditorSpellerInteropHasBeenDisposed","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/WinRTSpellerInterop.cs","lineNumber":110,"sourceCode":"\n        public override void  Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        /// <summary>\n        /// Internal interop resource cleanup\n        /// </summary>\n        /// <param name=\"disposing\">\n        ///     False when called from the Finalizer\n        ///     True when called explicitly from Dispose()\n        /// </param>\n        protected override void Dispose(bool disposing)\n        {\n            if (_isDisposed)\n            {\n                throw new ObjectDisposedException(SR.TextEditorSpellerInteropHasBeenDisposed);\n            }\n\n            try\n            {\n                // Ensure that Dispose is called from the UI thread\n                // If it is not, then make it so\n                if (BeginInvokeOnUIThread((Action<bool>)Dispose, DispatcherPriority.Normal, disposing) == null)\n                {\n                    // Already on UI thread\n                    // Continue with core Dispose logic\n\n                    ReleaseAllResources(disposing);\n                    _isDisposed = true;\n                }\n            }\n            catch (InvalidOperationException)\n            {\n                // We have no way determining whether or not this is running","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/WinRTSpellerInterop.cs#L92-L128","documentation":"WinRTSpellerInterop.Dispose(bool) throws ObjectDisposedException(SR.TextEditorSpellerInteropHasBeenDisposed) if Dispose is called when _isDisposed is already true. Double-dispose of the speller interop is treated as an error rather than idempotent.","triggerScenarios":"Calling Dispose() (or the finalizer path) a second time on the same WinRTSpellerInterop instance — e.g. explicit Dispose followed by a using block or container teardown.","commonSituations":"Owning object disposal chains that dispose the speller twice; finalizer racing with an explicit Dispose without the guard callers expect.","solutions":["Track your own disposed flag and skip the second Dispose call.","Call Dispose from exactly one place in your ownership chain.","Wrap in try/catch (ObjectDisposedException) when you can't control the disposal path."],"exampleFix":"// before\nspeller.Dispose();\nspeller.Dispose(); // throws\n// after\nif (!disposed) { speller.Dispose(); disposed = true; }","handlingStrategy":"try-catch","validationCode":"if (spellerDisposed) return;","typeGuard":null,"tryCatchPattern":"try { speller.Dispose(); } catch (ObjectDisposedException) { /* already disposed; ignore */ }","preventionTips":["Keep disposal single-owner: one place calls Dispose","Guard with your own disposed flag","Avoid finalizer + explicit Dispose double paths on this type"],"tags":["wpf","dispose","objectdisposed"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}