dotnet/wpf · error · InvalidOperationException

SR.Format(SR.XmlLangGetCultureFailure, lowerCaseTag)

Error message

SR.Format(SR.XmlLangGetCultureFailure, lowerCaseTag)

What it means

XmlLanguage.GetEquivalentCulture converts the IETF language tag into a CultureInfo via GetCultureInfoByIetfLanguageTag; when the tag is not a registered/valid language tag the underlying call throws ArgumentException, which is rethrown as an InvalidOperationException with the offending tag in the message and the original exception as InnerException.

Solutions

  1. Use TryGetEquivalentCulture instead of GetEquivalentCulture and handle the false return gracefully
  2. Pre-validate the tag with CultureInfo.GetCultures(CultureTypes.AllCultures) matching on IetfLanguageTag before calling
  3. Normalize the tag (lowercase, well-formed subtags) via XmlLanguage.GetLanguage before conversion
  4. Catch InvalidOperationException and fall back to InvariantCulture or a parent-language tag (e.g. "en" for "en-XYZ")

Example fix

// before
CultureInfo ci = xmlLang.GetEquivalentCulture(); // throws for unknown tag
// after
if (!xmlLang.TryGetEquivalentCulture(out CultureInfo ci))
    ci = CultureInfo.InvariantCulture;
Defensive patterns

Strategy: fallback

Validate before calling

bool tagKnown = CultureInfo.GetCultures(CultureTypes.AllCultures).Any(c => c.IetfLanguageTag == xmlLang.IetfLanguageTag);

Type guard

static bool HasEquivalentCulture(XmlLanguage lang) => lang != null && CultureInfo.GetCultures(CultureTypes.AllCultures).Any(c => c.IetfLanguageTag == lang.IetfLanguageTag);

Try / catch

try { ci = xmlLang.GetEquivalentCulture(); }
catch (InvalidOperationException ex) { ci = CultureInfo.InvariantCulture; /* log ex.InnerException */ }

Prevention

When it happens

Trigger: Calling GetEquivalentCulture on an XmlLanguage whose tag is empty, malformed, or not recognized by the OS culture data (e.g. "xx-YY" never registered, custom tags like "qps-plocm" on older systems, or an empty xml:lang).

Common situations: Deserializing localized documents where xml:lang was authored with made-up or legacy tags; user-supplied language strings passed into XmlLanguage.GetLanguage then converted; OS culture data differences across .NET/Windows versions making a tag valid on one machine and not another.

Related errors


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

Appendix: source

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

                // xml:lang="und"
                // see http://www.w3.org/International/questions/qa-no-language
                //
                // Just treat it the same as xml:lang=""
                if(string.Equals(lowerCaseTag, "und", StringComparison.Ordinal))
                {
                    lowerCaseTag = String.Empty;
                }            
                
                try
                {
                    // Even if we previously failed to find an EquivalentCulture, we retry, if only to
                    //   capture inner exception.
                    _equivalentCulture = CultureInfo.GetCultureInfoByIetfLanguageTag(lowerCaseTag);
                }
                catch (ArgumentException e)
                {
                    _equivalentCultureFailed = true;
                    throw new InvalidOperationException(SR.Format(SR.XmlLangGetCultureFailure, lowerCaseTag), e);
                }
            }

            return _equivalentCulture;
        }
        
        /// <summary>
        ///     Finds the most-closely-related non-neutral registered CultureInfo, if one is available.
        /// </summary>
        /// <returns>
        ///     A non-Neutral CultureInfo.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        ///    There is no related non-Neutral CultureInfo registered.
        /// </exception>
        /// <remarks>
        ///    Will return CultureInfo.InvariantCulture if-and-only-if this.Equals(XmlLanguage.Empty).
        ///    Finds the registered CultureInfo matching the longest-possible prefix of this XmlLanguage.

View on GitHub (pinned to 81131a70a4)