dotnet/wpf · error · ArgumentException

SR.FaceIndexMustBePositiveOrZero

Error message

SR.FaceIndexMustBePositiveOrZero

What it means

Util.SplitFontFaceIndex parses a '#<index>' fragment appended to a font URI to extract a TrueType collection face index. If the fragment exists but is not a non-negative integer parseable with NumberStyles.None, it throws ArgumentException with SR.FaceIndexMustBePositiveOrZero.

Solutions

  1. Use a plain non-negative integer in the URI fragment, e.g. 'MyFont.ttf#0' for the first face of a collection.
  2. If you meant to select a family, use the GlyphTypeface family-name constructor instead of a fragment.
  3. Strip or fix the fragment before constructing the Uri.
  4. Parse/validate the fragment with int.TryParse(NumberStyles.None, InvariantCulture) before passing the Uri.

Example fix

// before
var gt = new GlyphTypeface(new Uri("pack://application:,,,/Fonts/MyFont.ttf#My Family"));
// after
var gt = new GlyphTypeface(new Uri("pack://application:,,,/Fonts/MyFont.ttf#0")); // face index 0
Defensive patterns

Strategy: validation

Validate before calling

static bool HasValidFaceIndex(Uri fontUri, out int faceIndex)
{
    faceIndex = 0;
    string frag = fontUri.Fragment;
    if (string.IsNullOrEmpty(frag) || frag == "#") return true;
    return int.TryParse(frag.Substring(1), NumberStyles.None,
        CultureInfo.InvariantCulture, out faceIndex) && faceIndex >= 0;
}

Type guard

static bool IsNumericFaceFragment(Uri fontUri) =>
    fontUri.Fragment.Length > 1 &&
    uint.TryParse(fontUri.Fragment.Substring(1), NumberStyles.None,
        CultureInfo.InvariantCulture, out _);

Try / catch

try
{
    var gt = new GlyphTypeface(fontUri);
}
catch (ArgumentException ex) when (ex.Message.Contains("FaceIndex"))
{
    // fix: use numeric face index fragment like '#0', or family-name constructor
}

Prevention

When it happens

Trigger: Passing a GlyphTypeface/font Uri whose fragment (text after '#') is not a valid non-negative integer, e.g. 'pack://...:,,,/fonts/MyFont.ttf#face1' or 'MyFont.ttf#-2'.

Common situations: Hand-written font URIs where the author intended a font family name in the fragment (family-name syntax like 'MyFont.ttf#My Family') but the API expects a numeric collection face index; URL-encoded or localized digits in the fragment.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/FontCache/FontCacheUtil.cs:495

            // The only absolute URIs we allow in font family references are "file:" URIs.
            return absoluteUri.IsFile;
        }


        internal static void SplitFontFaceIndex(Uri fontUri, out Uri fontSourceUri, out int faceIndex)
        {
            // extract face index
            string fragment = fontUri.GetComponents(UriComponents.Fragment, UriFormat.SafeUnescaped);
            if (!String.IsNullOrEmpty(fragment))
            {
                if (!int.TryParse(
                        fragment,
                        NumberStyles.None,
                        CultureInfo.InvariantCulture,
                        out faceIndex
                    ))
                {
                    throw new ArgumentException(SR.FaceIndexMustBePositiveOrZero, nameof(fontUri));
                }

                // face index was specified in a fragment, we need to strip off fragment from the source Uri
                fontSourceUri = new Uri(fontUri.GetComponents(Util.UriWithoutFragment, UriFormat.SafeUnescaped));
            }
            else
            {
                // simple case, no face index specified
                faceIndex = 0;
                fontSourceUri = fontUri;
            }
        }

        internal static Uri CombineUriWithFaceIndex(string fontUri, int faceIndex)
        {
            if (faceIndex == 0)
                return new Uri(fontUri);

View on GitHub (pinned to 81131a70a4)