dotnet/wpf · error · XamlInternalException

SR.Format(SR.TemplateNotCollected, "WriteValue")

Error message

SR.Format(SR.TemplateNotCollected, "WriteValue")

What it means

XamlInternalException thrown by XamlDeferringWriter.WriteValue when the writer is in TemplateReady deferring mode, meaning a deferred template's node list exists but has not been collected/loaded yet, so writing a value at that point would corrupt the node stream. System.Xaml throws this because template deferral requires StartObject/EndObject transitions before values can be accepted.

Solutions

  1. Fix the node-stream ordering: ensure WriteStartObject/WriteEndObject (template collection) transitions occur before calling WriteValue in a deferred-template context.
  2. If the intent is to write values into the deferred template, use the deferred node list (XamlNodeList.Writer) rather than the outer deferring writer.
  3. Do not interleave direct Write* calls with deferred template collection on the same writer; complete one mode before switching.
  4. Treat this as a bug in the calling writer implementation — XamlInternalException indicates a violated internal protocol, not user input error.

Example fix

// before (wrong: WriteValue while template is ready but not collected)
writer.WriteStartObject(templateType);
writer.WriteValue("some value"); // throws XamlInternalException
// after
writer.WriteStartObject(templateType);
writer.WriteEndObject(); // complete the template collection transition first
writer.WriteValue("some value");
Defensive patterns

Strategy: validation

Validate before calling

if (deferringWriter.Mode == DeferringMode.TemplateReady)
    throw new InvalidOperationException("Complete template collection transitions before WriteValue.");

Type guard

static bool CanWriteValue(XamlDeferringWriter w) => w.Mode != DeferringMode.TemplateReady;

Try / catch

try { writer.WriteValue(v); }
catch (XamlInternalException ex) { LogProtocolBug(ex); throw; } // never swallow: indicates caller bug

Prevention

When it happens

Trigger: Calling WriteValue on a XamlDeferringWriter (obtained via XamlObjectWriterSettings/XamlXmlWriter template deferral) while _mode == DeferringMode.TemplateReady — i.e. after a deferred template has been prepared but before its node collection phase has started or completed.

Common situations: Custom XAML writers/readers that hand-craft node streams around markup-extension templates; feeding nodes out of order to a deferring writer; mixing a XamlNodeList-producing pipeline with direct Write* calls on the same writer.

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/108fb7db26fc46ec. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/InfosetObjects/DeferredWriter.cs:196

                _deferredWriter.WriteEndMember();
                _handled = true;
                break;

            default:
                throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), "WriteEndMember"));
            }
        }

        public override void WriteValue(object value)
        {
            _handled = false;
            switch (_mode)
            {
            case DeferringMode.Off:
                break;

            case DeferringMode.TemplateReady:
                throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, "WriteValue"));

            case DeferringMode.TemplateStarting:
                // This handles the case of SM template; V object; EM
                Debug.Assert(_deferredTreeDepth == 0);
                if (value is XamlNodeList)
                {
                    _deferredList = (XamlNodeList)value;
                    _mode = DeferringMode.TemplateReady;
                    _handled = true;
                }
                else
                {
                    StartDeferredList();
                    _mode = DeferringMode.TemplateDeferring;
                    goto case DeferringMode.TemplateDeferring;
                }

                break;

View on GitHub (pinned to 81131a70a4)