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
- Stop writing nodes once the writer is disposed; move any remaining writes before Dispose.
- Check the writer's IsDisposed state before each write in defensive code paths.
- Ensure only one component owns the writer lifecycle so Dispose is not called while writes are still pending.
- 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
- Write all nodes before Dispose
- Give one component ownership of writer disposal
- Check IsDisposed before late writes
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
- SR.HwndSourceDisposed
- SR.ParserTypeConverterTextUnusable
- XamlXmlWriterException(SR.Format(SR.XamlXmlWriterWriteNotSup…
- XamlXmlWriterException(SR.Format(SR.XamlXmlWriterWriteNotSup…
- ' '.' ' is a property without a getter and is not a valid…
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)