dotnet/wpf · error · InvalidOperationException

SR.ParserCompatDuplicate formatted with (oldXmlns…

Error message

SR.ParserCompatDuplicate formatted with (oldXmlns, newXmlns) - duplicate XmlnsCompatibleWithAttribute mapping for the same old namespace

What it means

XmlnsCache throws InvalidOperationException when two XmlnsCompatibleWithAttribute declarations map the same OldNamespace to different NewNamespace values. The compatibility table (_compatTable) can hold only one new-namespace mapping per old namespace, so a conflicting second mapping is ambiguous and rejected.

Solutions

  1. Find all XmlnsCompatibleWithAttribute declarations whose OldNamespace matches the oldXmlns in the message and remove or correct the conflicting one
  2. Ensure only one NewNamespace is declared per OldNamespace across all referenced assemblies
  3. Remove stale compatibility shims from older library versions still referenced by the project
  4. If both mappings are needed for different scenarios, split the assemblies so both are never loaded together in the same XAML compilation

Example fix

// before
[assembly: XmlnsCompatibleWith("clr-namespace:Lib.V1", "clr-namespace:Lib.V2")]
[assembly: XmlnsCompatibleWith("clr-namespace:Lib.V1", "clr-namespace:Lib.V3")] // conflict

// after
[assembly: XmlnsCompatibleWith("clr-namespace:Lib.V1", "clr-namespace:Lib.V3")]
Defensive patterns

Strategy: validation

Validate before calling

var seen = new Dictionary<string,string>();
foreach (var a in assemblies.SelectMany(a => a.GetCustomAttributes<XmlnsCompatibleWithAttribute>()))
{
    if (seen.TryGetValue(a.OldNamespace, out var prev) && prev != a.NewNamespace)
        throw new InvalidOperationException($"Conflicting XmlnsCompatibleWith mapping for {a.OldNamespace}");
    seen[a.OldNamespace] = a.NewNamespace;
}

Prevention

When it happens

Trigger: Calling AddReferencedAssemblies or GetMappingArray while scanning assemblies containing e.g. [assembly: XmlnsCompatibleWith("old-ns", "ns-A")] in one assembly and [assembly: XmlnsCompatibleWith("old-ns", "ns-B")] in another (or the same) assembly.

Common situations: Referencing two versions of a control library that each declare a different compatibility target for the same old namespace; a library rename where an old compatibility shim was left alongside the new mapping.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XmlnsCache.cs:393

                                                typeof(XmlnsCompatibleWithAttribute));
#endif

                for(int attrIdx=0; attrIdx<attributes.Length; attrIdx++)
                {
                    string oldXmlns = null;
                    string newXmlns = null;

                    GetNamespacesFromCompatAttr(attributes[attrIdx], out oldXmlns, out newXmlns);

                    if (String.IsNullOrEmpty(oldXmlns) || String.IsNullOrEmpty(newXmlns))
                    {
                        throw new ArgumentException(SR.Format(SR.ParserAttributeArgsLow, "XmlnsCompatibleWithAttribute"));
                    }

                    if (_compatTable.ContainsKey(oldXmlns) &&
                        _compatTable[oldXmlns] != newXmlns)
                    {
                        throw new InvalidOperationException(SR.Format(SR.ParserCompatDuplicate, oldXmlns,
                                                                   _compatTable[oldXmlns]));
                    }
                    _compatTable[oldXmlns] = newXmlns;
                    _compatTableReverse[newXmlns] = oldXmlns;
                }
            }
        }

        // Table where Xml namespace is the key, and value is a list of assembly / clrns pairs
        private HybridDictionary _cacheTable = null;

        // Table where old namespaces are the key, and new namespaces are the value
        private Dictionary<string, string> _compatTable = null;

        // Table where new namespaces are the key, and old namespaces are the value
        private Dictionary<string, string> _compatTableReverse = null;

#if !PBTCOMPILER

View on GitHub (pinned to 81131a70a4)