{"record":{"id":"984c661afba554c5","repo":"dotnet/wpf","slug":"sr-xmlnscompatcycle","errorCode":null,"errorMessage":"SR.XmlnsCompatCycle","messagePattern":"SR\\.XmlnsCompatCycle","errorType":"exception","errorClass":"XamlSchemaException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/MS/Impl/XmlNsInfo.cs","lineNumber":473,"sourceCode":"                _nsInfo = nsInfo;\n\n                // Calculate the subsume count upfront, since this also serves as our cycle detection\n                _subsumeCount = new Dictionary<string, int>(nsInfo.OldToNewNs.Count);\n\n                HashSet<string> visited = new HashSet<string>();\n\n                // for every XmlnsCompatAttribute\n                foreach (string newNs in nsInfo.OldToNewNs.Values)\n                {\n                    visited.Clear();\n\n                    // Increment the subsume count for all transitive subsumers\n                    string ns = newNs;\n                    do\n                    {\n                        if (!visited.Add(ns))\n                        {\n                            throw new XamlSchemaException(SR.Format(SR.XmlnsCompatCycle, assembly.FullName, ns));\n                        }\n\n                        IncrementSubsumeCount(ns);\n                        ns = GetNewNs(ns);\n                    }\n                    while (ns is not null);\n                }\n            }\n\n            public int CompareNamespacesByPreference(string ns1, string ns2)\n            {\n                if (KS.Eq(ns1, ns2))\n                {\n                    return 0;\n                }\n\n                const int Prefer_NS1 = -1;\n                const int Prefer_NS2 = 1;","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/MS/Impl/XmlNsInfo.cs#L455-L491","documentation":"System.Xaml throws XamlSchemaException(SR.XmlnsCompatCycle) when the old-to-new namespace mapping defined by XmlnsCompat attributes contains a cycle (e.g. nsA -> nsB -> nsA). NamespaceComparer walks the chain to compute transitive subsumption counts and detects a repeated namespace via the visited set.","triggerScenarios":"Assembly-level XmlnsCompat attributes form a loop such that GetNewNs(ns) eventually returns a namespace already visited; encountered in NamespaceComparer while ordering namespaces.","commonSituations":"Namespace refactors done in both directions (A->B and B->A attributes kept simultaneously), merged assembly attributes from different branches each mapping the namespaces toward their own version.","solutions":["Break the cycle by removing or correcting one XmlnsCompat mapping so the chain is acyclic and ends at the current namespace.","Keep only mappings that point strictly from older to newer namespaces, one direction only.","Audit all assemblies' XmlnsCompat attributes after namespace migrations for conflicting directions."],"exampleFix":"// before (cycle)\n[assembly: XmlnsCompat(\"clr-namespace:A\", \"clr-namespace:B\")]\n[assembly: XmlnsCompat(\"clr-namespace:B\", \"clr-namespace:A\")]\n// after (acyclic)\n[assembly: XmlnsCompat(\"clr-namespace:A\", \"clr-namespace:B\")]","handlingStrategy":"validation","validationCode":"var map = new Dictionary<string,string> { [\"clr-namespace:A\"]=\"clr-namespace:B\" }; var seen = new HashSet<string>(); var ns = startNs; while (ns != null && map.ContainsKey(ns)) { if (!seen.Add(ns)) throw new InvalidOperationException(\"XmlnsCompat cycle at \" + ns); ns = map[ns]; }","typeGuard":null,"tryCatchPattern":"try { loadXaml(); } catch (XamlSchemaException ex) when (ex.Message.Contains(\"XmlnsCompatCycle\")) { /* remove the cyclic mapping */ }","preventionTips":["Always map old -> newer namespaces in a single direction only","Remove obsolete compat attributes once the old namespace is gone"],"tags":["xaml","assembly-attributes","cycle-detection"],"backgroundTag":"internal-invariant-violation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}