dotnet/wpf · error · ArgumentException
PropertyOfClassCannotBeNull (Typeface, TextRunProperties)
Error message
PropertyOfClassCannotBeNull (Typeface, TextRunProperties)
What it means
FetchTextRun finally checks that properties.Typeface is non-null and throws ArgumentException(SR.PropertyOfClassCannotBeNull with Typeface/TextRunProperties). The typeface drives glyph selection and run shaping, so it is mandatory per-run.
Solutions
- Set Typeface on the run's TextRunProperties (e.g. new Typeface("Segoe UI"))
- Resolve fonts via FontFamily/Typeface combination rather than leaving null
- Validate each run's properties in your TextSource before returning it
Example fix
// before
public override Typeface Typeface => null;
// after
public override Typeface Typeface => new Typeface("Segoe UI"); Defensive patterns
Strategy: type-guard
Validate before calling
if (run.Properties?.Typeface == null) run.Properties.Typeface = new Typeface("Segoe UI"); Type guard
bool HasTypeface(TextRun r) => r?.Properties?.Typeface != null;
Try / catch
try { formatter.FormatLine(...); } catch (ArgumentException) { /* set typeface and retry */ } Prevention
- Always set Typeface in TextRunProperties implementations
- Handle font resolution failures so fallbacks never leave Typeface null
When it happens
Trigger: A TextRun whose TextRunProperties.Typeface is null is fetched by the run cache during line formatting.
Common situations: Custom TextRunProperties not initializing Typeface; fallback font resolution failing silently and leaving null; copy constructors omitting the typeface field.
Understand the failure class
Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.
Related errors
- paragraphProperties.DefaultTextRunProperties.Typeface
- PropertyOfClassCannotBeNull (CultureInfo, TextRunProperties)
- SR.TextRunPropertiesCannotBeNull
- Animation_ChildMustBeKeyFrame
- Animation_DependencyPropertyIsNotAnimatable
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/584fcb8dd1e7fb0a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/TextRunCacheImp.cs:131
if (properties == null)
throw new ArgumentException(SR.TextRunPropertiesCannotBeNull);
if (properties.FontRenderingEmSize <= 0)
throw new ArgumentException(SR.Format(SR.PropertyOfClassMustBeGreaterThanZero, "FontRenderingEmSize", "TextRunProperties"));
double realMaxFontRenderingEmSize = Constants.RealInfiniteWidth / Constants.GreatestMutiplierOfEm;
if (properties.FontRenderingEmSize > realMaxFontRenderingEmSize)
throw new ArgumentException(SR.Format(SR.PropertyOfClassCannotBeGreaterThan, "FontRenderingEmSize", "TextRunProperties", realMaxFontRenderingEmSize));
CultureInfo culture = CultureMapper.GetSpecificCulture(properties.CultureInfo);
if (culture == null)
throw new ArgumentException(SR.Format(SR.PropertyOfClassCannotBeNull, "CultureInfo", "TextRunProperties"));
if (properties.Typeface == null)
throw new ArgumentException(SR.Format(SR.PropertyOfClassCannotBeNull, "Typeface", "TextRunProperties"));
}
//
// TextRun is specifial to SpanVector because TextRun also encodes position which needs to be
// consistent with the positions encoded by SpanVector. In run cache, the begining of a span
// should always correspond to the begining of a cached text run. If the end of the currently fetched
// run overlaps with the begining of an already cached run, the begining of the cached run needs to be
// adjusted as well as its span. Because we can't gurantee the correctness of the overlapped range
// so we'll simply remove the overlapped runs here.
//
// Move the rider to the end of the current run
textRunSpanRider.At(cpFetch + textRun.Length - 1);
_latestPosition = textRunSpanRider.SpanPosition;
if (textRunSpanRider.CurrentElement != _textRunVector.Default)
{View on GitHub (pinned to 81131a70a4)