dotnet/wpf · error · XamlParseException
SR.InvalidClosingBracketCharacers
Error message
SR.InvalidClosingBracketCharacers
What it means
MeScanner.ReadString tracks a stack of open bracket characters inside a markup-extension string. When a closing bracket arrives (e.g. ')' or ']') that does not match the bracket currently on top of the stack, the scanner throws XamlParseException with SR.InvalidClosingBracketCharacers, naming the offending character. This keeps brace/bracket nesting inside `{}` values unambiguous so System.Xaml can tell extension boundaries from literal text.
Solutions
- Balance the brackets in the value so every closer matches the most recently opened bracket.
- Escape literal braces with a leading {} sequence if the text is not meant to be a markup extension.
- Move bracket-heavy literal values into a resource (resx/ResourceDictionary) and reference them, avoiding inline parsing.
- Check the reported character and its position in the attribute value; remove or escape the stray closer.
Example fix
<!-- before -->
<TextBox Text="{StaticResource Pattern)]}" />
<!-- after -->
<TextBox Text="{StaticResource Pattern}" /> Defensive patterns
Strategy: validation
Validate before calling
static bool BracketsBalanced(string value) { int depth = 0; foreach (var c in value) { if (c=='('||c=='[') depth++; if (c==')'||c==']') depth--; if (depth<0) return false; } return depth==0; } Try / catch
try { return XamlReader.Parse(xaml); } catch (XamlParseException ex) when (ex.Message.Contains("bracket")) { return null; } Prevention
- Validate bracket balance of attribute values before Load
- Escape literal brackets or move them into resources
- Use round-trip designer output rather than manual edits
When it happens
Trigger: Parsing XAML where a markup extension string contains a closing bracket without its matching opener, e.g. `Text="{StaticResource Key)]}"` or nested `{x:Static Member=...)}` where a ')' appears with only '[' opened.
Common situations: Copy-pasted XAML where literal ')' text was not escaped; template or code-generated markup with mismatched bracket pairs; values like regular expressions or format strings containing brackets pasted into markup extensions unescaped.
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
- SR.MalformedBracketCharacters
- brokenRule (SR.UnexpectedToken-based parser rule error)
- SR.MalformedPropertyName
- SR.QuoteCharactersOutOfPlace
- SR.UnclosedQuote
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/6096bb28eb33bc7b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Parser/MeScanner.cs:400
// If we are inside of MarkupExtensionBracketCharacters for a particular property or position parameter,
// scoop up everything inside one by one, and keep track of nested Bracket Characters in the stack.
else if (_context.CurrentBracketModeParseParameters is not null && _context.CurrentBracketModeParseParameters.IsBracketEscapeMode)
{
Stack<char> bracketCharacterStack = _context.CurrentBracketModeParseParameters.BracketCharacterStack;
if (_currentSpecialBracketCharacters.StartsEscapeSequence(ch))
{
bracketCharacterStack.Push(ch);
}
else if (_currentSpecialBracketCharacters.EndsEscapeSequence(ch))
{
if (_currentSpecialBracketCharacters.Match(bracketCharacterStack.Peek(), ch))
{
bracketCharacterStack.Pop();
}
else
{
throw new XamlParseException(this, SR.Format(SR.InvalidClosingBracketCharacers, ch.ToString()));
}
}
else if (ch == Backslash)
{
escaped = true;
}
if (bracketCharacterStack.Count == 0)
{
_context.CurrentBracketModeParseParameters.IsBracketEscapeMode = false;
}
if (!escaped)
{
sb.Append(ch);
}
}
elseView on GitHub (pinned to 81131a70a4)