dotnet/wpf · error · InvalidOperationException

InvalidOperationException(SR.Format(SR.XamlXmlWriterWriteNot…

Error message

InvalidOperationException(SR.Format(SR.XamlXmlWriterWriteNotSupportedInCurrentState, "WriteEndObject"))

What it means

On WriteEndObject the writer pops the current namespace-scope frame and validates that the frame was created by a StartObject or GetObject node. If the frame's AllocatingNodeType is something else (e.g. created for a member or value), the object being ended does not correspond to an object start, so it throws InvalidOperationException 'WriteEndObject not supported in current state'. This protects the element nesting of the emitted XML.

Solutions

  1. Ensure every WriteEndObject matches a prior WriteStartObject or WriteGetObject at the same frame level
  2. End any open members (WriteEndMember) before WriteEndObject
  3. Log/balance node emissions in the writing loop to detect mismatches early

Example fix

// before
writer.WriteStartMember(m);
writer.WriteEndObject(); // wrong frame -> throws
// after
writer.WriteStartMember(m);
writer.WriteEndMember();
writer.WriteEndObject();
Defensive patterns

Strategy: validation

Validate before calling

if (openFrameAllocatedBy != "StartObject" && openFrameAllocatedBy != "GetObject") throw new InvalidOperationException("WriteEndObject requires an object frame");

Type guard

bool CanWriteEndObject(XamlNodeType frameAllocType) => frameAllocType is XamlNodeType.StartObject or XamlNodeType.GetObject;

Try / catch

try { writer.WriteEndObject(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("WriteEndObject")) { /* rebalance frames: close member or abort */ }

Prevention

When it happens

Trigger: Calling XamlXmlWriter.WriteEndObject when the innermost frame was allocated by WriteStartMember/WriteValue rather than WriteStartObject/WriteGetObject — i.e. mismatched start/end pairs.

Common situations: Hand-rolled node loops where an EndObject is emitted after a member without closing the member first; error-recovery code that skips starts but still emits ends; duplicated WriteEndObject calls.

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


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/f1afe9c7c8ae42be. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlXmlWriter.cs:1092

                    }

                    writer.ppStateInfo.ReturnState = State;
                    writer.currentState = ExpandPositionalParameters.State;
                }
                else
                {
                    writer.currentState = InMember.State;
                }
            }

            public override void WriteEndObject(XamlXmlWriter writer)
            {
                Debug.Assert(writer.namespaceScopes.Count > 0);
                Frame frame = writer.namespaceScopes.Pop();
                if (frame.AllocatingNodeType != XamlNodeType.StartObject &&
                    frame.AllocatingNodeType != XamlNodeType.GetObject)
                {
                    throw new InvalidOperationException(SR.Format(SR.XamlXmlWriterWriteNotSupportedInCurrentState, "WriteEndObject"));
                }

                if (!frame.IsObjectFromMember)
                {
                    writer.output.WriteEndElement();
                }

                if (writer.namespaceScopes.Count > 0)
                {
                    writer.currentState = InMemberAfterEndObject.State;
                }
                else
                {
                    writer.Flush();
                    writer.currentState = End.State;
                }
            }
        }

View on GitHub (pinned to 81131a70a4)