dotnet/wpf · error · InvalidOperationException

SR.TextFormatterReentranceProhibited

Error message

SR.TextFormatterReentranceProhibited

What it means

AcquireContext throws InvalidOperationException(SR.TextFormatterReentranceProhibited) when the same TextFormatter instance is reentered during optimal break computation. A TextFormatter instance allows only one formatting context at a time; nesting optimal-break content requires a separate TextFormatter per nesting level.

Solutions

  1. Create a new TextFormatter instance for each nesting level of optimal break content
  2. Use TextFormatter.Create() inside your TextSource callbacks instead of the shared instance
  3. Restructure the TextSource so it does not reenter FormatLine during formatting

Example fix

// before
class MySource : TextSource {
    TextFormatter _fmt = TextFormatter.Create(); // shared
    public override TextRun GetTextRun(int i) { _fmt.FormatLine(...); } // reentrancy
}
// after
class MySource : TextSource {
    public override TextRun GetTextRun(int i) {
        using (var inner = TextFormatter.Create()) { /* format nested content */ }
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (_formattingInProgress && ReferenceEquals(currentFormatter, this)) throw new InvalidOperationException("Reentrancy detected; use a new TextFormatter per nesting level");

Try / catch

try { formatter.FormatLine(...); } catch (InvalidOperationException) { var nested = TextFormatter.Create(); /* retry with nested formatter */ }

Prevention

When it happens

Trigger: Calling TextFormatter.FormatLine again (directly or via TextSource callbacks) on the same TextFormatter instance while an optimal-break formatting operation is already in progress.

Common situations: A TextSource implementation that itself calls into the same TextFormatter to build runs; recursive layout where the same shared TextFormatter singleton is used at multiple nesting levels of optimal-break content.

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


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/367714a7e467a08c. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/TextFormatterImp.cs:549

            }

            if (c == contextCount)
            {
                if (contextCount == 0 || !_multipleContextProhibited)
                {
                    //  no free one exists, create a new one
                    context = new TextFormatterContext();
                    _contextList.Add(context);
                }
                else
                {
                    // This instance of TextFormatter only allows a single context, reentering the
                    // same TextFormatter in this case is not allowed.
                    //
                    // This requirement is currently enforced only during optimal break computation.
                    // Client implementing nesting of optimal break content inside another must create
                    // a separate TextFormatter instance for each content in different nesting level.
                    throw new InvalidOperationException(SR.TextFormatterReentranceProhibited);
                }
            }

            Debug.Assert(context != null);

            context.Owner = owner;
            return context;
        }


        /// <summary>
        /// Create an anti-inversion transform from the inversion flags.
        /// The result is used to correct glyph bitmap on an output to
        /// a drawing surface with the specified inversions applied on.
        /// </summary>
        internal static MatrixTransform CreateAntiInversionTransform(
            InvertAxes  inversion,
            double      paragraphWidth,

View on GitHub (pinned to 81131a70a4)