dotnet/wpf · error · ArgumentException

SR.CompileFeatureSet_InvalidTypographyProperties

Error message

SR.CompileFeatureSet_InvalidTypographyProperties

What it means

CompileFeatureSet in LineServicesRun throws ArgumentException(SR.CompileFeatureSet_InvalidTypographyProperties) when the first run has null TypographyProperties but at least one other run in the batch has non-null TypographyProperties. OpenType feature compilation requires all runs in the group to agree: either all null (no typography features) or all carrying properties.

Solutions

  1. Ensure every TextRun returned by your TextSource sets the same TypographyProperties state (all set, or all default).
  2. For runs without custom typography, provide an empty/default TextRunTypographyProperties instance instead of leaving null when neighbors have one.
  3. Split runs into separate lines/segments so runs with and without typography properties are not compiled together.

Example fix

// before
yield return new TextRun(cch, runLength, propsWithoutTypography);
yield return new TextRun(cch + n, n, propsWithTypography);
// after
var props1 = propsWithoutTypography; // give run 1 the same TextRunTypographyProperties as run 2
yield return new TextRun(cch, runLength, props1);
yield return new TextRun(cch + n, n, propsWithTypography);
Defensive patterns

Strategy: validation

Validate before calling

// ensure consistency across all runs in a line
bool anyTyped = runs.Any(r => r.TextRunProperties.TypographyProperties != null);
foreach (var run in runs)
    if (anyTyped && run.TextRunProperties.TypographyProperties == null)
        run.TextRunProperties.TypographyProperties = new TextRunTypographyProperties(); // or drop typography everywhere

Type guard

bool TypographyConsistent(IList<TextRun> runs) =>
    runs.All(r => r.TextRunProperties.TypographyProperties == null) ||
    runs.All(r => r.TextRunProperties.TypographyProperties != null);

Try / catch

try { formatter.FormatLine(source, start, width, paraProps, lineBreak); }
catch (ArgumentException ex) when (ex.Message.Contains("typography")) { /* strip typography from all runs and retry */ }

Prevention

When it happens

Trigger: Formatting/merging multiple lsruns (e.g. during CompileFeatureSet over a run array) where TextRunProperties.TypographyProperties is set on some runs but not the first one — mixed typography settings across adjacent runs in one line.

Common situations: Custom TextSource returning TextFormattingRunProperties where some runs carry TextRunTypographyProperties (ligatures, swashes) and adjacent runs use default properties; partial migration to custom typography; fonts/styling applied per-span inconsistently.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/LineServicesRun.cs:918

            int*                      pcchRuns,
            uint                      totalLength,
            out DWriteFontFeature[][] fontFeatures,
            out uint[]                fontFeatureRanges
            )
        {           
            Debug.Assert(lsruns != null && lsruns.Length > 0 && lsruns[0] != null);

            //
            //  Quick check for null properties
            //  Run properties should be all null or all not null
            //   
            if (lsruns[0].RunProp.TypographyProperties == null)
            {
                for (int i = 1; i < lsruns.Length; i++)
                {
                    if (lsruns[i].RunProp.TypographyProperties != null)
                    {
                        throw new ArgumentException(SR.CompileFeatureSet_InvalidTypographyProperties);
                    }
                }

                fontFeatures      = null;
                fontFeatureRanges = null;
                return;
            }
            //End of quick check. We will process custom features now.
                

            fontFeatures      = new DWriteFontFeature[lsruns.Length][];
            fontFeatureRanges = new uint[lsruns.Length];

            for (int i = 0; i < lsruns.Length; i++)
            {
                TextRunTypographyProperties properties = lsruns[i].RunProp.TypographyProperties;
                fontFeatures[i] = CreateDWriteFontFeatures(properties);
                fontFeatureRanges[i] = checked((uint)pcchRuns[i]);

View on GitHub (pinned to 81131a70a4)