dotnet/wpf · error · ObjectDisposedException
SR.TextBreakpointHasBeenDisposed
Error message
SR.TextBreakpointHasBeenDisposed
What it means
FullTextBreakpoint.GetTextLineBreak throws ObjectDisposedException with SR.TextBreakpointHasBeenDisposed when the breakpoint's backing TextLine has already been disposed. WPF's text formatter disposes internal line/breakpoint objects after paragraph layout completes or a new formatting pass invalidates them; accessing them afterwards is invalid.
Solutions
- Extract all needed data (line break, metrics) before disposing the TextLine; do not hold the breakpoint across disposal.
- Cache extracted data (TextLineBreak values, metrics) instead of the live TextBreakpoint object.
- Re-format the line via TextFormatter if you need its breakpoint after it was disposed.
- Guard access with a disposed check and re-create the breakpoint when needed.
Example fix
// before
TextLineBreak brk;
using (line) { }
brk = breakpoint.GetTextLineBreak(); // ObjectDisposedException
// after
TextLineBreak brk;
using (line)
{
brk = breakpoint.GetTextLineBreak(); // capture before disposal
} Defensive patterns
Strategy: validation
Validate before calling
// capture data before disposal var brk = line.GetTextLineBreak(); // while line is alive
Type guard
bool BreakpointUsable(TextBreakpoint bp) => bp is { } && !bp.IsDisposed; // if exposed; otherwise track your own flag Try / catch
try { brk = breakpoint.GetTextLineBreak(); }
catch (ObjectDisposedException)
{
line = formatter.FormatLine(...); // re-format
brk = line.GetTextLineBreak();
} Prevention
- Extract TextLineBreak data inside the formatting scope.
- Cache extracted data, not live TextLine/TextBreakpoint objects.
- Do not dispose lines the formatter or breakpoints still reference.
- Track a disposed flag on cached text objects.
When it happens
Trigger: Calling GetTextLineBreak() on a TextBreakpoint stored from a previous line/paragraph after the owning TextLine was disposed (e.g. after calling Dispose on the line, or after the formatter reused/disposed it during custom TextSource GetTextRunForLine flows).
Common situations: Custom TextSource implementations caching TextLineBreak/TextLine objects beyond one layout pass; deferred use of a breakpoint in background formatting; accessing cached lines after the paragraph was re-formatted.
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
- EncryptedPackageEnvelope object was disposed.
- SR.StorageBasedPackagePropertiesDiposed
- SR.StreamObjectDisposed
- SR.StreamObjectDisposed
- SR.TextLineHasBeenDisposed
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/2f0a3ec5fce2cf9d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/FullTextBreakpoint.cs:217
_penaltyResource = IntPtr.Zero;
_isDisposed = true;
GC.KeepAlive(this);
}
}
#region TextBreakpoint
/// <summary>
/// Client to acquire a state at the point where breakpoint is determined by line breaking process;
/// can be null when the line ends by the ending of the paragraph. Client may pass this
/// value back to TextFormatter as an input argument to TextFormatter.FormatParagraphBreakpoints when
/// formatting the next set of breakpoints within the same paragraph.
/// </summary>
public override TextLineBreak GetTextLineBreak()
{
if (_isDisposed)
{
throw new ObjectDisposedException(SR.TextBreakpointHasBeenDisposed);
}
return _metrics.GetTextLineBreak(_ploline);
}
/// <summary>
/// Client to get the handle of the internal factors that are used to determine penalty of this breakpoint.
/// </summary>
/// <remarks>
/// Calling this method means that the client will now manage the lifetime of this unmanaged resource themselves using unsafe penalty handler.
/// We would make a correspondent call to notify our unmanaged wrapper to release them from duty of managing this
/// resource.
/// </remarks>
internal override IntPtr GetTextPenaltyResource()
{
if (_isDisposed)
{
throw new ObjectDisposedException(SR.TextBreakpointHasBeenDisposed);View on GitHub (pinned to 81131a70a4)