dotnet/maui · error · BuildException

XC0003

XC0003

Error message

Missing mandatory property "{0}" on "{1}".

What it means

XC0003 PropertyMissing thrown by the DataTemplateExtension compiled markup extension when the required 'TypeName' property is absent. The extension first checks node.Properties for a 'TypeName' key, then falls back to the first collection item. If neither yields a ValueNode (e.g. the property is missing and there are no collection items, or the item is an element node rather than a value), the build fails.

Source

Thrown at src/Controls/src/Build.Tasks/CompiledMarkupExtensions/DataTemplateExtension.cs:23

using Mono.Cecil;
using Mono.Cecil.Cil;
using static Mono.Cecil.Cil.Instruction;
using static Mono.Cecil.Cil.OpCodes;

namespace Microsoft.Maui.Controls.Build.Tasks
{
	class DataTemplateExtension : ICompiledMarkupExtension
	{
		public IEnumerable<Instruction> ProvideValue(ElementNode node, ModuleDefinition module, ILContext context, out TypeReference typeRef)
		{
			typeRef = module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "DataTemplate"));
			var name = new XmlName("", "TypeName");

			if (!node.Properties.TryGetValue(name, out INode typeNameNode) && node.CollectionItems.Any())
				typeNameNode = node.CollectionItems[0];

			if (typeNameNode is not ValueNode valueNode)
				throw new BuildException(BuildExceptionCode.PropertyMissing, node as IXmlLineInfo, null, "TypeName", typeof(Microsoft.Maui.Controls.Xaml.DataTemplateExtension));

			var contentTypeRef = module.ImportReference(XmlTypeExtensions.GetTypeReference(context.Cache, valueNode.Value as string, module, node as BaseNode))
				?? throw new BuildException(BuildExceptionCode.TypeResolution, node as IXmlLineInfo, null, valueNode.Value);

			var dataTemplateCtor = module.ImportCtorReference(context.Cache, typeRef, new[] { module.ImportReference(context.Cache, ("mscorlib", "System", "Type")) });
			return [
				Create(Ldtoken, module.ImportReference(contentTypeRef)),
				Create(Call, module.ImportMethodReference(context.Cache, ("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true)),
				Create(Newobj, dataTemplateCtor),
			];
		}
	}
}

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Add the TypeName attribute to the DataTemplate extension usage, e.g. {DataTemplate TypeName='local:MyView'}.
  2. Ensure the TypeName value is a simple string (ValueNode) representing a type reference, not a nested element.
  3. If using inline syntax, ensure the first child item is a value node with the type name.

Example fix

<!-- before -->
<DataTemplate />

<!-- after -->
<DataTemplate TypeName="local:MyItemView" />
Defensive patterns

Strategy: validation

Validate before calling

// Validate that a DataTemplate extension node has a TypeName property or collection item
static bool HasTypeNameValue(IDictionary<XmlName, INode> properties, IList<INode> collectionItems)
    => (properties.TryGetValue(new XmlName("", "TypeName"), out var node) && node is ValueNode)
       || (collectionItems.Any() && collectionItems[0] is ValueNode);

Prevention

When it happens

Trigger: Using {DataTemplate} markup extension without specifying TypeName, or providing a non-value node where TypeName is expected. The extension requires either TypeName="MyType" as an attribute or a inline value as the first child item.

Common situations: Forgetting to include TypeName when using the {DataTemplate} extension. Providing a complex element instead of a simple type-name string. Confusing this compiled extension with the runtime DataTemplate API which accepts a Type object directly.

Related errors


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