dotnet/wpf · error · InvalidOperationException

SR.Format(SR.XmlLangGetSpecificCulture, _lowerCaseTag)

Error message

SR.Format(SR.XmlLangGetSpecificCulture, _lowerCaseTag)

What it means

XmlLanguage.GetSpecificCulture derives a specific (region-qualified) culture from the equivalent culture; when the compatible culture's IetfLanguageTag is empty (i.e. it corresponds to the invariant culture) there is no specific culture to create, so it throws InvalidOperationException naming the original tag.

Solutions

  1. Guard against XmlLanguage.Empty / empty IetfLanguageTag before calling GetSpecificCulture and use CultureInfo.InvariantCulture directly instead
  2. Ensure the document or property carries a real xml:lang value (e.g. "en-US") rather than an empty string
  3. Catch InvalidOperationException and fall back to CurrentCulture for formatting/sorting
  4. Use GetEquivalentCulture/TryGetEquivalentCulture when only language (not region) matters

Example fix

// before
CultureInfo specific = xmlLang.GetSpecificCulture(); // throws for empty tag
// after
CultureInfo specific = xmlLang.IetfLanguageTag.Length == 0
    ? CultureInfo.InvariantCulture
    : xmlLang.GetSpecificCulture();
Defensive patterns

Strategy: type-guard

Validate before calling

bool canGetSpecific = xmlLang != null && xmlLang.IetfLanguageTag.Length > 0;

Type guard

static bool HasSpecificCulture(XmlLanguage lang) => lang != null && lang != XmlLanguage.Empty && lang.IetfLanguageTag.Length > 0;

Try / catch

try { ci = xmlLang.GetSpecificCulture(); }
catch (InvalidOperationException) { ci = CultureInfo.CurrentCulture; }

Prevention

When it happens

Trigger: Calling GetSpecificCulture on an XmlLanguage built from an empty or unrecognized tag whose GetCompatibleCulture resolves to the invariant culture (empty IetfLanguageTag).

Common situations: Binding code that calls GetSpecificCulture for sorting/formatting on documents with empty or invalid xml:lang; passing CultureInfo.InvariantCulture-derived languages through localization pipelines; default XmlLanguage.Empty being used in GetCultureInfo paths.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Markup/XmlLanguage.cs:236

        ///    Finds the registered CultureInfo matching the longest-possible prefix of this XmlLanguage.
        ///       If that registered CultureInfo is Neutral, then relies on
        ///       CultureInfo.CreateSpecificCulture() to map from a Neutral CultureInfo to a Specific one.
        /// </remarks>
        public CultureInfo GetSpecificCulture()
        {
            if (_specificCulture == null)
            {
                if (_lowerCaseTag.Length == 0 || string.Equals(_lowerCaseTag, "und", StringComparison.Ordinal))
                {
                    _specificCulture = GetEquivalentCulture();
                }
                else
                {
                    CultureInfo culture = GetCompatibleCulture();

                    if (culture.IetfLanguageTag.Length == 0)
                    {
                        throw new InvalidOperationException(SR.Format(SR.XmlLangGetSpecificCulture, _lowerCaseTag));
                    }

                    if (!culture.IsNeutralCulture)
                    {
                        _specificCulture = culture;
                    }
                    else
                    {
                        try
                        {
                            // note that it's important that we use culture.Name, not culture.IetfLanguageTag, here
                            culture = CultureInfo.CreateSpecificCulture(culture.Name);
                            _specificCulture = CultureInfo.GetCultureInfoByIetfLanguageTag(culture.IetfLanguageTag);
                        }
                        catch (ArgumentException e)
                        {
                            throw new InvalidOperationException(SR.Format(SR.XmlLangGetSpecificCulture, _lowerCaseTag), e);
                        }

View on GitHub (pinned to 81131a70a4)