dotnet/maui · error · BuildException

XC0066

XC0066

Error message

Invalid Xaml "Protected Xmlns {xmlNamespace}. Can't add assembly {assemblyName}."

What it means

Raised when an assembly tries to register itself into one of the protected XML namespaces (the MAUI uri or the XAML 2009 uri) via a XmlnsDefinitionAttribute, but its assembly name does not begin with Microsoft/System/mscorlib. Those namespaces are reserved for the framework, so the build task rejects the registration as invalid XAML.

Solutions

  1. Change the XmlnsDefinition attribute to use your own custom uri, e.g. 'http://mycompany.com/schemas/mylib'.
  2. If you only want a clr-namespace shortcut, register under an unreserved uri and reference the clr-namespace directly in XAML.
  3. Remove the XmlnsDefinition attribute entirely if you do not need a custom xmlns prefix for your controls.

Example fix

// before
[assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/2021/maui", "MyLib.Controls")]
// after
[assembly: XmlnsDefinition("http://mycompany.com/schemas/mylib", "MyLib.Controls")]
Defensive patterns

Strategy: validation

Validate before calling

// Assembly-level guard: never register a third-party assembly into a reserved xmlns.
static readonly HashSet<string> Reserved = new() { XamlParser.MauiUri, XamlParser.X2009Uri };
static string SafeXmlns(string desired, string assemblyName)
    => Reserved.Contains(desired) && !assemblyName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)
        ? $"http://{assemblyName.ToLowerInvariant()}.local/schemas"
        : desired;

Prevention

When it happens

Trigger: ValidateProtectedXmlns is called with xmlNamespace equal to XamlParser.MauiUri or XamlParser.X2009Uri and an assemblyName that does not StartsWith Microsoft/System/mscorlib (case-insensitive), reaching the final throw.

Common situations: A third-party library copies a Maui sample assembly attribute and reuses 'http://schemas.microsoft.com/dotnet/2021/maui' as its XmlnsDefinition; a library targets the XAML 2009 namespace intentionally; a generated assembly accidentally emits the reserved uri.

Related errors


AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13). Data as JSON: /api/errors/a9c492e587ae5d2b. Report an issue: GitHub.

Appendix: source

Thrown at src/Controls/src/Build.Tasks/XmlTypeExtensions.cs:62

						xmlnsDefinitions.Add(attribute);
					}
			}

			return xmlnsDefinitions;
		}
		static void ValidateProtectedXmlns(string xmlNamespace, string assemblyName)
		{
			//maui, and x: xmlns are protected
			if (xmlNamespace != XamlParser.MauiUri && xmlNamespace != XamlParser.X2009Uri)
				return;

			//we know thos assemblies, they are fine in maui or x xmlns
			if (assemblyName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase)
				|| assemblyName.StartsWith("System", StringComparison.OrdinalIgnoreCase)
				|| assemblyName.StartsWith("mscorlib", StringComparison.OrdinalIgnoreCase))
				return;

			throw new BuildException(BuildExceptionCode.InvalidXaml, null, null,
				$"Protected Xmlns {xmlNamespace}. Can't add assembly {assemblyName}.");

		}
		static void GatherXmlnsDefinitionAttributes(List<XmlnsDefinitionAttribute> xmlnsDefinitions, AssemblyDefinition asmDef, AssemblyDefinition currentAssembly)
		{
			foreach (var ca in asmDef.CustomAttributes)
			{
				if (ca.AttributeType.FullName == _xmlnsDefinitionName)
				{
					var attr = GetXmlnsDefinition(ca, asmDef);
					//only add globalxmlns definition from the current assembly
					if (attr.XmlNamespace == XamlParser.MauiGlobalUri
						&& asmDef != currentAssembly)
						continue;
					ValidateProtectedXmlns(attr.XmlNamespace, attr.AssemblyName);
					xmlnsDefinitions.Add(attr);
				}
			}

View on GitHub (pinned to f377ff1c5e)