dotnet/maui · error · BuildException

XC0123

XC0123

Error message

Source property is not a string literal.

What it means

Thrown when a Source attribute is present on <StyleSheet> but its value is not a string literal ValueNode. The provider emits a resource lookup from a literal path string, so a non-literal (element/binding) value cannot be compiled.

Source

Thrown at src/Controls/src/Build.Tasks/CompiledValueProviders/StyleSheetProvider.cs:36

				((ElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.MauiUri, "Source"), out sourceNode);

			INode styleNode = null;
			if (!((ElementNode)node).Properties.TryGetValue(new XmlName("", "Style"), out styleNode) &&
				!((ElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.MauiUri, "Style"), out styleNode) &&
				((ElementNode)node).CollectionItems.Count == 1)
				styleNode = ((ElementNode)node).CollectionItems[0];

			if (sourceNode != null && styleNode != null)
				throw new BuildException(BuildExceptionCode.StyleSheetSourceOrContent, node, null);

			if (sourceNode == null && styleNode == null)
				throw new BuildException(BuildExceptionCode.StyleSheetNoSourceOrContent, node, null);

			if (styleNode != null && styleNode is not ValueNode)
				throw new BuildException(BuildExceptionCode.StyleSheetStyleNotALiteral, node, null);

			if (sourceNode != null && sourceNode is not ValueNode)
				throw new BuildException(BuildExceptionCode.StyleSheetSourceNotALiteral, node, null);

			if (styleNode != null)
			{
				var style = (styleNode as ValueNode).Value as string;
				yield return Create(Ldstr, style);
				yield return Create(Call, module.ImportMethodReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.StyleSheets", "StyleSheet"),
																	   methodName: "FromString",
																	   parameterTypes: [("mscorlib", "System", "String")],
																	   isStatic: true));
			}
			else
			{
				var source = (sourceNode as ValueNode)?.Value as string;
				INode rootNode = node;
				while (rootNode is not ILRootNode)
					rootNode = rootNode.Parent;

				var rootTargetPath = RDSourceTypeConverter.GetPathForType(context, module, ((ILRootNode)rootNode).TypeReference);

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Use a plain literal string for Source, e.g. Source="Resources/Styles/app.css".
  2. If runtime selection is required, load the StyleSheet in code-behind instead of via Source.
  3. For per-platform files, conditionally include different <StyleSheet Source="..." /> elements or resolve in code.

Example fix

// before
<StyleSheet Source="{Binding CssPath}" />
// after
<StyleSheet Source="Resources/Styles/app.css" />
Defensive patterns

Strategy: validation

Validate before calling

// Lint: StyleSheet Source must be a literal, not a binding
static bool StyleSheetSourceIsLiteral(XElement el) {
    var src = el.Attribute("Source")?.Value;
    return src == null || (!src.StartsWith("{") && !src.Contains("{"));
}

Prevention

When it happens

Trigger: Binding the Source path: <StyleSheet Source="{Binding CssPath}" />; using a nested element as the Source value; OnPlatform/OnIdiom wrapping the path.

Common situations: Wanting to choose the stylesheet file at runtime; copy-paste that replaced the literal with a markup expression; IDE refactoring that bound the attribute.

Related errors


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