dotnet/wpf · error · ArgumentException
TextObjectMetrics_WidthOutOfRange
Error message
TextObjectMetrics_WidthOutOfRange
What it means
TextStore throws ArgumentException(SR.TextObjectMetrics_WidthOutOfRange) when the formatter produces a text-object metrics width larger than the maximum computable value LS supports (IdealToReal(Constants.IdealInfiniteWidth - currentPosition)). This guards against LS returning an unrepresentable width for a text object (e.g. a TextElement/text modifiers value). It is an internal invariant guard inside TextObjectMetrics handling, not a caller-input validation.
Solutions
- Reduce the size/extent of the text object being formatted (font size, run length) so its width stays within the ideal-coordinate maximum
- Check PixelsPerDip / scaling factors and zoom levels applied to the formatting; extreme values inflate widths
- Capture a minimal repro of the text content and file a WPF bug, since LS cannot compute widths beyond its maximum value
- Wrap the formatting call in try-catch to fail gracefully instead of crashing the layout pass
Example fix
// before: formatting a run with fontSize = 1e6 at deep zoom
// after: clamp scale before formatting
double maxIdeal = Constants.IdealInfiniteWidth;
if (estimatedWidth > maxIdeal) { fontSize = ComputeMaxFittingFontSize(); } Defensive patterns
Strategy: try-catch
Validate before calling
// estimate before formatting
double maxIdeal = Constants.IdealInfiniteWidth - currentPosition;
double maxReal = formatter.IdealToReal(maxIdeal, pixelsPerDip);
if (estimatedTextObjectWidth > maxReal) { /* reduce font size / run length */ } Try / catch
try { textStore.FormatTextObject(...); }
catch (ArgumentException ex) when (ex.Message == SR.TextObjectMetrics_WidthOutOfRange)
{ logger.Warn("Text object width exceeds LS maximum"); FallBackToSmallerScale(); } Prevention
- Clamp font sizes and zoom/PixelsPerDip factors before layout
- Avoid extremely long unbreakable text objects in a single run
- Log estimated metrics widths in diagnostics to catch near-limit values early
When it happens
Trigger: Calling text layout APIs (e.g. TextFormatter-based formatting through TextStore) where a text object's computed metrics width exceeds Constants.IdealInfiniteWidth measured from the current character position, typically with extremely large font sizes, extremely long unbreakable text objects, or corrupted/oversized text run data.
Common situations: Rendering documents with absurdly large em sizes or DIP scaling (PixelsPerDip) pushing widths beyond ideal-coordinate limits; hosting WPF text services (TSF) with pathological text objects; internal-only, rarely hit by direct developers.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Collection_CopyTo_NumberOfElementsExceedsArrayLength
- ArgumentOutOfRangeException (timeout was Duration.Automatic)
- Collection_BadRank
- Collection_CopyTo_ArrayCannotBeMultidimensional
- Collection_CopyTo_ArrayCannotBeMultidimensional
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/090de7d8a7ab47ff.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/TextFormatting/TextStore.cs:2362
widthLeft = rightMargin - _formatWidth;
}
metrics = textObject.Format(_settings.Formatter.IdealToReal(widthLeft, _settings.TextSource.PixelsPerDip));
if (Double.IsPositiveInfinity(metrics.Width))
{
// If the inline object has Width to be positive infinity, trim the width to
// the maximum value that LS can handle.
metrics = new TextEmbeddedObjectMetrics(
_settings.Formatter.IdealToReal((Constants.IdealInfiniteWidth - currentPosition), _settings.TextSource.PixelsPerDip),
metrics.Height,
metrics.Baseline
);
}
else if (metrics.Width > _settings.Formatter.IdealToReal((Constants.IdealInfiniteWidth - currentPosition), _settings.TextSource.PixelsPerDip))
{
// LS cannot compute value greater than its maximum computable value
throw new ArgumentException(SR.TextObjectMetrics_WidthOutOfRange);
}
_textObjectMetricsVector.SetReference(cpFirst, textObject.Length, metrics);
}
Debug.Assert(metrics != null);
return metrics;
}
#region ENUMERATIONS & CONST
// first negative cp of bullet marker
internal const int LscpFirstMarker = (-0x7FFFFFFF);
// Note: Trident uses this figure
internal const int TypicalCharactersPerLine = 100;
View on GitHub (pinned to 81131a70a4)