dotnet/wpf · error · PtsException

SR.Format(SR.PTSError, fserr)

Error message

SR.Format(SR.PTSError, fserr)

What it means

Pts.cs throws a PtsException wrapping the native Windows PTS (pager/text-services) error code returned by the unmanaged layout engine. The default case (SR.PTSError) fires when the native component returns an error code that is not one of the specifically translated codes (like tserrPageTooLong or tserrSystemRestrictionsExceeded). It indicates the flow-document layout engine hit an unexpected internal failure while validating the result of a native call.

Solutions

  1. Inspect the fserr value in the PtsException message and match it against the tserr* constants in Pts.cs to identify the native failure
  2. Check the FlowDocument for changes made to the logical tree during measure/arrange and defer them via Dispatcher to after layout
  3. Reproduce with a smaller document and validate content (e.g. malformed Table or FixedDocument structures)
  4. Repair or reinstall the .NET/WPF runtime if the native ptscomponents library is corrupted

Example fix

// before
Dispatcher.Invoke(() => document.Blocks.Add(newParagraph)); // during layout
// after
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => document.Blocks.Add(newParagraph)));
Defensive patterns

Strategy: try-catch

Validate before calling

// PtsException is only thrown after a native call fails; pre-validate document structure instead
if (flowDocument == null || flowDocument.Blocks == null) throw new InvalidOperationException("FlowDocument not initialized");

Try / catch

try
{
    /* measure/paginate FlowDocument */
}
catch (PtsException ex)
{
    logger.LogError(ex, "PTS native layout failed with code {Code}", ex.HResult);
    // abort pagination and fall back to re-layout with a fresh document copy
}

Prevention

When it happens

Trigger: Calling Validate -> ValidateAndTrace -> Validate on a PtsContext whose native PTS call (page/table/track layout) returns an unmapped fserr code, e.g. a non-fserrNone result from the unmanaged milcore/pts host during FlowDocument measure or page layout.

Common situations: Corrupt or very large FlowDocument content causing the native paginator to fail; memory pressure in the native layout engine; unexpected content change during layout (illegal tree change) leaving PTS state inconsistent; native resource limits hit with codes not covered by dedicated messages.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/PtsHost/Pts.cs:73

                case fserrCallbackException:
                    Debug.Assert(ptsContext != null, "Null argument 'ptsContext' - required for return value validation.");
                    if (ptsContext != null)
                    {
                        SecondaryException se = new SecondaryException(ptsContext.CallbackException);
                        ptsContext.CallbackException = null;
                        throw se;
                    }
                    else
                    {
                        throw new Exception(SR.Format(SR.PTSError, fserr));
                    }

                case tserrPageTooLong:
                case tserrSystemRestrictionsExceeded:
                    throw new PtsException(SR.Format(SR.FormatRestrictionsExceeded, fserr));

                default:
                    throw new PtsException(SR.Format(SR.PTSError, fserr));
            }
        }
        internal static void ValidateAndTrace(int fserr, PtsContext ptsContext)
        {
            if (fserr != fserrNone) 
            { 
                ErrorTrace(fserr, ptsContext); 
            }
        }
        private static void ErrorTrace(int fserr, PtsContext ptsContext)
        {
            switch (fserr)
            {
                case fserrOutOfMemory:
                    throw new OutOfMemoryException();

                default:
                    Debug.Assert(ptsContext != null, "Null argument 'ptsContext' - required for return value validation."); 

View on GitHub (pinned to 81131a70a4)