dotnet/wpf · error · FormatException

SR.InvalidLocCommentValue

Error message

SR.InvalidLocCommentValue

What it means

LocalizationComments.ParsePropertyComments parses Localization.Comment attribute strings of the form 'PropertyName(Comment text)'. This FormatException is thrown when, outside a comment and not inside a property-name token, a non-whitespace character appears that is not an unescaped comment start '(' — i.e. the value text is malformed before any comment begins.

Solutions

  1. Wrap every comment value in parentheses: Property(Comment).
  2. Escape literal '(' or ')' inside comments with a backslash: '\('.
  3. Remove any non-whitespace characters between the property name and the opening parenthesis.
  4. Escape a literal backslash as '\\' so it is not treated as an escape character.

Example fix

// before
[Localization.Comments]
Text This is the header comment
// after
[Localization.Comments]
Text(This is the header comment)
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidLocCommentValue(string v)
{
    if (string.IsNullOrEmpty(v)) return false;
    int i = 0;
    while (i < v.Length)
    {
        char c = v[i];
        if (c == '\\') { i += 2; continue; }
        if (c == '(')
        {
            i++;
            while (i < v.Length && v[i] != ')')
            {
                if (v[i] == '\\') i++;
                else if (v[i] == '(') return false;
                i++;
            }
            if (i >= v.Length) return false;
        }
        else if (!char.IsWhiteSpace(c) && i > 0 && v[i-1] == ' ') return false;
        i++;
    }
    return true;
}

Try / catch

try { ParsePropertyComments(input); } catch (FormatException ex) { log.Warn($"Malformed Localization.Comments value '{input}': {ex.Message}"); }

Prevention

When it happens

Trigger: Calling ParsePropertyComments (via the pairs iterator over Localization.Comments) with input where stray characters precede the '(' comment start, e.g. 'Text Some comment' instead of 'Text(Some comment)', or an unescaped ')' terminating a comment followed by junk.

Common situations: Hand-edited [Localization.Comments] attributes in .baml/XAML projects, values copied from documentation with the parentheses stripped or with extra prose before the '(', and localization resource files edited by non-IDE tools.

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/2f69a9c4dc0902e0. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Globalization/LocalizationComments.cs:144

                            escaped = false;
                        }
                    }
                }
                else
                {
                    // parsing the "Value" part
                    if (tokenBuffer.Length == 0)
                    {
                        if (input[i] == CommentStart && !escaped)
                        {
                            // comment must begin with unescaped CommentStart
                            tokenBuffer.Append(input[i]);
                            escaped = false;
                        }
                        else if (!Char.IsWhiteSpace(input[i]))
                        {
                            // else, only white space is allows before an unescaped comment start char
                            throw new FormatException(SR.Format(SR.InvalidLocCommentValue, currentPair.PropertyName, input));
                        }
                    }
                    else
                    {
                        // inside the comment
                        if (input[i] == CommentEnd)
                        {
                            if (!escaped)
                            {
                                // terminated by unescaped Comment
                                currentPair.Value = tokenBuffer.ToString(1, tokenBuffer.Length - 1);
                                tokens.Add(currentPair);
                                tokenBuffer.Clear();
                                currentPair = new PropertyComment();
                            }
                            else
                            {
                                // continue on escaped end char

View on GitHub (pinned to 81131a70a4)