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

  1. Reduce the size/extent of the text object being formatted (font size, run length) so its width stays within the ideal-coordinate maximum
  2. Check PixelsPerDip / scaling factors and zoom levels applied to the formatting; extreme values inflate widths
  3. Capture a minimal repro of the text content and file a WPF bug, since LS cannot compute widths beyond its maximum value
  4. 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

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


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)