dotnet/wpf · error · ObjectDisposedException
SR.TextEditorSpellerInteropHasBeenDisposed
Error message
SR.TextEditorSpellerInteropHasBeenDisposed
What it means
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.
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.
Example fix
// before
speller.Dispose();
speller.Dispose(); // throws
// after
if (!disposed) { speller.Dispose(); disposed = true; } Defensive patterns
Strategy: try-catch
Validate before calling
if (spellerDisposed) return;
Try / catch
try { speller.Dispose(); } catch (ObjectDisposedException) { /* already disposed; ignore */ } Prevention
- Keep disposal single-owner: one place calls Dispose
- Guard with your own disposed flag
- Avoid finalizer + explicit Dispose double paths on this type
When it happens
Trigger: 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.
Common situations: Owning object disposal chains that dispose the speller twice; finalizer racing with an explicit Dispose without the guard callers expect.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- NLGSpellerInterop.SpellerSegment
- NLGSpellerInterop.SpellerSentence
- SR.DataSpaceManagerDisposed
- SR.StreamObjectDisposed
- SR.TextEditorSpellerInteropHasBeenDisposed
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/91df9af91f39a2aa.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/WinRTSpellerInterop.cs:110
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Internal interop resource cleanup
/// </summary>
/// <param name="disposing">
/// False when called from the Finalizer
/// True when called explicitly from Dispose()
/// </param>
protected override void Dispose(bool disposing)
{
if (_isDisposed)
{
throw new ObjectDisposedException(SR.TextEditorSpellerInteropHasBeenDisposed);
}
try
{
// Ensure that Dispose is called from the UI thread
// If it is not, then make it so
if (BeginInvokeOnUIThread((Action<bool>)Dispose, DispatcherPriority.Normal, disposing) == null)
{
// Already on UI thread
// Continue with core Dispose logic
ReleaseAllResources(disposing);
_isDisposed = true;
}
}
catch (InvalidOperationException)
{
// We have no way determining whether or not this is runningView on GitHub (pinned to 81131a70a4)