dotnet/wpf · error · InvalidOperationException
SR.XamlMarkupExtensionWriterInputInvalid
Error message
SR.XamlMarkupExtensionWriterInputInvalid
What it means
WriteEndObject pops a node from the internal node stack to match the end object against its start object. If the stack is empty there is no matching StartObject, meaning the writer received an EndObject without a corresponding StartObject — an invalid XAML node stream. The library throws InvalidOperationException with XamlMarkupExtensionWriterInputInvalid.
Solutions
- Ensure every WriteEndObject is paired with exactly one prior WriteStartObject for the same object
- Validate/normalize the XAML node stream before forwarding it (e.g. with a custom XamlWriter that checks balance)
- Wrap the writing pass in try/catch for InvalidOperationException and log the offending node sequence
Example fix
// before
if (nodeType == XamlNodeType.EndObject) writer.WriteEndObject(); // no state check
// after
if (nodeType == XamlNodeType.EndObject && startObjectDepth > 0) { startObjectDepth--; writer.WriteEndObject(); } Defensive patterns
Strategy: validation
Validate before calling
if (startObjectDepth <= 0) throw new InvalidOperationException("WriteEndObject called without an open StartObject"); Type guard
bool CanEndObject => startObjectDepth > 0;
Try / catch
try { writer.WriteEndObject(); }
catch (InvalidOperationException ex) when (ex.Message == SR.XamlMarkupExtensionWriterInputInvalid || ex.Message.Contains("markup extension")) { /* fix stream pairing */ } Prevention
- Maintain a depth counter for StartObject/EndObject in forwarding code
- Never forward EndObject nodes from a filtered stream unless StartObject was forwarded
- Replay streams through XamlNodeList to normalize before writing
When it happens
Trigger: Calling XamlMarkupExtensionWriter.WriteEndObject() (or forwarding an EndObject node) before any WriteStartElement/WriteStartObject for the object has been issued, or calling it more times than StartObject was called.
Common situations: Hand-written node-stream emission that is off by one; a node-stream filter that drops StartObject nodes but forwards EndObject; replaying a truncated XAML node stream.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- NotImplementedException(SR.MissingCaseXamlNodes)
- NotSupportedException(SR.MissingCaseXamlNodes)
- SR.Format(SR.TemplateNotCollected, "WriteValue")
- SR.XamlFactoryInvalidXamlNode
- XamlXmlWriterException(SR.Format(SR.XamlXmlWriterDuplicateMe…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/32cdd3d6cba1f7a5.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlMarkupExtensionWriter.cs:337
writer.nodes.Push(new Node { NodeType = XamlNodeType.StartObject, XamlType = type });
writer.currentState = InObjectBeforeMember.State;
}
}
private abstract class InObject : WriterState
{
protected InObject() { }
public abstract string Delimiter
{
get;
}
public override void WriteEndObject(XamlMarkupExtensionWriter writer)
{
if (writer.nodes.Count == 0)
{
throw new InvalidOperationException(SR.XamlMarkupExtensionWriterInputInvalid);
}
Node node = writer.nodes.Pop();
if (node.NodeType != XamlNodeType.StartObject)
{
throw new InvalidOperationException(SR.XamlMarkupExtensionWriterInputInvalid);
}
writer.sb.Append('}');
if (writer.nodes.Count == 0)
{
writer.currentState = Start.State;
}
else
{
Node member = writer.nodes.Peek();View on GitHub (pinned to 81131a70a4)