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
- Use a plain literal string for Source, e.g. Source="Resources/Styles/app.css".
- If runtime selection is required, load the StyleSheet in code-behind instead of via Source.
- 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
- Keep Source a plain relative resource path string.
- Resolve dynamic stylesheet selection in code-behind.
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.