dotnet/wpf · error · XamlInternalException
SR.Format(SR.TemplateNotCollected, "WriteEndObject")
Error message
SR.Format(SR.TemplateNotCollected, "WriteEndObject")
What it means
XamlInternalException with SR.TemplateNotCollected thrown from DeferredWriter.WriteEndObject when the writer is in DeferringMode.TemplateReady. Ending an object while in TemplateReady state means the writer expected the template content collection to begin, not terminate an object.
Solutions
- Ensure WriteStartObject/WriteEndObject calls are balanced and that template content begins via the TemplateStarting path before ending objects
- Replay the node stream through the standard XamlServices.Save/deferring reader-writer chain rather than hand-emitting
- Recreate the DeferredWriter to reset _mode to Off after a failed write sequence
- Catch XamlInternalException during template serialization and validate the node stream with a XamlXmlWriter in non-deferring mode first
Example fix
// before // writer in TemplateReady writer.WriteEndObject(); // TemplateNotCollected // after // emit template content first (TemplateStarting -> TemplateDeferring), then end objects writer.WriteStartObject(type); writer.WriteEndObject(); // balanced inside deferred region
Defensive patterns
Strategy: try-catch
Try / catch
try { deferringWriter.WriteEndObject(); }
catch (XamlInternalException ex) { log.Error("WriteEndObject in TemplateReady state: {0}", ex.Message); } Prevention
- Verify StartObject/EndObject pairing before entering template regions
- Emit template content via the TemplateStarting path before ending objects
- Dry-run node streams through XamlXmlWriter to catch imbalance early
- Discard and recreate a writer left in TemplateReady after an error
When it happens
Trigger: WriteEndObject called on a deferring writer whose _mode == TemplateReady — e.g. the node stream closed an object right after the template was armed but before StartDeferredList entered TemplateDeferring, leaving no matching deferred object to end.
Common situations: Unbalanced WriteStartObject/WriteEndObject pairs in custom node-stream generators; a skipped object-start due to an earlier TemplateReady error leaving the state machine behind; templates serialized without their opening object nodes.
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
- SR.Format(SR.MissingCase, _mode.ToString(), methodName)
- SR.Format(SR.MissingCase, _mode.ToString()…
- SR.Format(SR.MissingCase, _mode.ToString()…
- SR.Format(SR.MissingCase, _mode.ToString(), "WriteMember")
- SR.Format(SR.TemplateNotCollected, methodName)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/d60b3ad60affa4dc.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/InfosetObjects/DeferredWriter.cs:116
_deferredTreeDepth += 1;
_handled = true;
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), methodName));
}
}
public override void WriteEndObject()
{
_handled = false;
switch (_mode)
{
case DeferringMode.Off:
break;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, "WriteEndObject"));
case DeferringMode.TemplateDeferring:
_deferredWriter.WriteEndObject();
_handled = true;
_deferredTreeDepth -= 1;
if (_deferredTreeDepth == 0)
{
_deferredWriter.Close();
_deferredWriter = null;
_mode = DeferringMode.TemplateReady;
}
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), "WriteEndObject"));
}View on GitHub (pinned to 81131a70a4)