dotnet/wpf · error · XamlException

SR.WriterIsClosed

Error message

SR.WriterIsClosed

What it means

WriterDelegate.Dispose installs a replacement _addDelegate that throws XamlException(SR.WriterIsClosed), so any node submitted to the writer after disposal fails. The delegate forwarding wrapper signals EndOfStream to the sink on dispose and then permanently closes its input.

Solutions

  1. Stop writing nodes once the writer is disposed; move any remaining writes before Dispose.
  2. Check the writer's IsDisposed state before each write in defensive code paths.
  3. Ensure only one component owns the writer lifecycle so Dispose is not called while writes are still pending.
  4. Catch XamlException for WriterIsClosed if post-dispose writes must be tolerated.

Example fix

// before
using (var w = new WriterDelegate(...)) { w.WriteEndMember(); }
w.WriteEndMember(); // throws
// after
using (var w = new WriterDelegate(...)) { w.WriteEndMember(); } // all writes inside the using
Defensive patterns

Strategy: try-catch

Validate before calling

if (writer.IsDisposed) throw new InvalidOperationException("Cannot write to a disposed WriterDelegate.");

Type guard

bool CanWrite(WriterDelegate w) => !w.IsDisposed;

Try / catch

try { writer.WriteStartMember(p); } catch (XamlException ex) when (/* WriterIsClosed */) { /* stop the pipeline; writer already disposed */ }

Prevention

When it happens

Trigger: Calling any Write* method on the XamlWriter wrapper after Dispose() has run, which routes through the replaced throwing delegate.

Common situations: Using a writer after a using block or after the reader that owns it was disposed; buffered/writer chains where both owner and consumer call Dispose and later code still writes; exception-path cleanup followed by attempted final writes.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/WriterDelegate.cs:76

        {
            ThrowIsDisposed();
            _addDelegate(XamlNodeType.Value, value);
        }

        public override void WriteNamespace(NamespaceDeclaration namespaceDeclaration)
        {
            ThrowIsDisposed();
            _addDelegate(XamlNodeType.NamespaceDeclaration, namespaceDeclaration);
        }

        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing && !IsDisposed)
                {
                    _addDelegate(XamlNodeType.None, XamlNode.InternalNodeType.EndOfStream);
                    _addDelegate = delegate { throw new XamlException(SR.WriterIsClosed); };
                    if (_addLineInfoDelegate is not null)
                    {
                        _addLineInfoDelegate = delegate { throw new XamlException(SR.WriterIsClosed); };
                    }
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }

        public override XamlSchemaContext SchemaContext
        {
            get { return _schemaContext; }
        }
        #endregion

View on GitHub (pinned to 81131a70a4)