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

  1. Ensure WriteStartObject/WriteEndObject calls are balanced and that template content begins via the TemplateStarting path before ending objects
  2. Replay the node stream through the standard XamlServices.Save/deferring reader-writer chain rather than hand-emitting
  3. Recreate the DeferredWriter to reset _mode to Off after a failed write sequence
  4. 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

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


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)