dotnet/wpf · error · InvalidOperationException
SR.ParserDictionarySealed (the dictionary is sealed and…
Error message
SR.ParserDictionarySealed (the dictionary is sealed and cannot be modified)
What it means
XmlnsDictionary.CheckSealed throws InvalidOperationException when the dictionary is read-only (sealed, typically because its owning ParserContext has been frozen after parsing). Sealed dictionaries may no longer be mutated: Clear, PushScope, PopScope, AddNamespace, and RemoveNamespace all funnel through this check.
Solutions
- Create a new ParserContext / XmlnsDictionary for each parse instead of mutating a sealed one
- Clone the sealed dictionary via the copy constructor new XmlnsDictionary(sealedDict) — the copy is mutable — then modify the copy
- Check IsReadOnly before mutating and take the copy path when true
Example fix
// before
cachedContext.XmlnsDictionary.AddNamespace("x", "http://example.com/x"); // throws if sealed
// after
var dict = cachedContext.XmlnsDictionary.IsReadOnly
? new XmlnsDictionary(cachedContext.XmlnsDictionary)
: cachedContext.XmlnsDictionary;
dict.AddNamespace("x", "http://example.com/x"); Defensive patterns
Strategy: validation
Validate before calling
if (dict.IsReadOnly)
dict = new XmlnsDictionary(dict); // mutable copy
else
dict.PushScope(); Type guard
bool IsMutable(XmlnsDictionary d) => !d.IsReadOnly;
Try / catch
try { dict.AddNamespace("x", nsUri); }
catch (InvalidOperationException) { dict = new XmlnsDictionary(dict); dict.AddNamespace("x", nsUri); } Prevention
- Check IsReadOnly before any mutation call
- Never reuse a ParserContext across parse sessions for mutation; create a fresh one
- Clone sealed dictionaries with the copy constructor instead of mutating them
When it happens
Trigger: Calling Clear, PushScope, PopScope, AddNamespace, RemoveNamespace, Add, or the indexer setter on an XmlnsDictionary whose IsReadOnly is true (e.g. ParserContext.XmlnsDictionary of a context that finished parsing or was sealed).
Common situations: Reusing a cached ParserContext across multiple XAML parse operations and trying to register new namespaces on it; mutating a dictionary captured from a completed parse session.
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
- IAmbientProvider
- IXamlSchemaContextProvider
- SR.FrameworkElementFactoryCannotAddText
- SR.NameScopeOnRootInstance
- 0x80040209
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/0bdfac328e81c8c3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XmlnsDictionary.cs:594
#region Private
private void Initialize()
{
// We set the initial array to 8 and double from there when we run of the space.
// For the start case, we set the DefaultNamespaceuri to null.
_nsDeclarations = new NamespaceDeclaration[8];
_nsDeclarations[0].Prefix = string.Empty;
_nsDeclarations[0].Uri = null;
_nsDeclarations[0].ScopeCount = 0;
_lastDecl = 0;
_countDecl = 0;
}
private void CheckSealed()
{
if (IsReadOnly)
{
throw new InvalidOperationException(SR.ParserDictionarySealed);
}
}
/// <summary>
/// Helper to Add Namespace - Checks for prefix from rear.
/// If exists : override it locally, if not Adds an entry.
/// </summary>
/// <param name="prefix">prefix to add</param>
/// <param name="xmlNamespace">namespace uri string to add</param>
private void AddNamespace(string prefix, string xmlNamespace)
{
CheckSealed();
if (xmlNamespace == null)
throw new ArgumentNullException(nameof(xmlNamespace));
if (prefix == null)
throw new ArgumentNullException(nameof(prefix));View on GitHub (pinned to 81131a70a4)