dotnet/wpf · error · XamlUnexpectedParseException
EmptyElement ::= . EMPTYELEMENT DIRECTIVE* ATTRIBUTE*.
Error message
EmptyElement ::= . EMPTYELEMENT DIRECTIVE* ATTRIBUTE*.
What it means
XamlPullParser.P_EmptyElement implements `EmptyElement ::= EMPTYELEMENT DIRECTIVE* ATTRIBUTE*`. It throws XamlUnexpectedParseException when the scanner's current NodeType is not EMPTYELEMENT, since this method may only run when a self-closing element token (<Tag/>) is current. The check enforces the parser's grammar contract that P_Element dispatches to P_EmptyElement only for empty-element tokens.
Solutions
- If using a custom scanner, ensure it sets NodeType to EMPTYELEMENT exactly for self-closing tags.
- Do not call P_EmptyElement directly; always go through P_Element which validates the node type.
- Validate the XAML is well-formed XML before parsing.
- Update to a patched System.Xaml/WPF version if a scanner-state bug is suspected.
Example fix
// before: direct call with wrong node state parser.P_EmptyElement(); // after: go through the validating dispatcher parser.P_Element();
Defensive patterns
Strategy: try-catch
Try / catch
try { return XamlReader.Parse(xaml); } catch (XamlUnexpectedParseException ex) { Log($"Grammar violation at {ex.LineNumber}:{ex.LinePosition}"); return null; } Prevention
- Never call P_EmptyElement outside P_Element
- Custom scanners must emit EMPTYELEMENT only for self-closing tags
- Add scanner unit tests against the grammar
When it happens
Trigger: P_Element dispatching to the empty-element branch while the scanner holds another node type — possible with a custom/injected scanner or reordered node stream; in normal use only from corrupted scanner state or non-well-formed input.
Common situations: Custom XamlReader/scanner implementations violating the ScannerNodeType contract; testing harnesses calling P_EmptyElement directly with the wrong current node; parser bugs after scanner state corruption.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- StartElement ::= . ELEMENT DIRECTIVE*.
- Element ::= . EmptyElement | ( StartElement ElementBody ).
- ElementBody ::= ATTRIBUTE* ( PropertyElement | Content )* …
- EmptyPropertyElement ::= EMPTYPROPERTYELEMENT.
- NonemptyPropertyElement ::= . PROPERTYELEMENT Content?…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/fce142c08c950495.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Parser/XamlPullParser.cs:125
foreach (XamlNode node in P_ElementBody())
{
yield return node;
}
break;
default:
throw new XamlUnexpectedParseException(_xamlScanner, nodeType, ElementRuleException);
}
}
///////////////////////////
// EmptyElement ::= EMPTYELEMENT DIRECTIVE* ATTRIBUTE*
//
public IEnumerable<XamlNode> P_EmptyElement()
{
if (_xamlScanner.NodeType != ScannerNodeType.EMPTYELEMENT)
{
throw new XamlUnexpectedParseException(_xamlScanner, _xamlScanner.NodeType,
EmptyElementRuleException);
}
yield return Logic_StartObject(_xamlScanner.Type, _xamlScanner.Namespace);
_xamlScanner.Read();
if (ProvideLineInfo)
{
yield return Logic_LineInfo();
}
while (_xamlScanner.NodeType == ScannerNodeType.DIRECTIVE)
{
// Directives are processed exactly like Attributes.
foreach (XamlNode node in LogicStream_Attribute())
{
yield return node;
}
View on GitHub (pinned to 81131a70a4)