dotnet/maui · error · BuildException
XC0127
XC0127
Error message
x:Key expects a string literal.
What it means
Thrown inside CanAddToResourceDictionary when an entry has an x:Key but its node is not a ValueNode (i.e. not a string literal). The compiler requires ResourceDictionary keys to be plain string literals; a markup/element key is rejected.
Source
Thrown at src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs:1932
if (paramType.FullName == "System.Object" && varValue.VariableType.IsValueType)
return true;
return CanAddToResourceDictionary(parent, propertyType, elementNode, lineInfo, context);
}
static bool CanAddToResourceDictionary(VariableDefinition parent, TypeReference collectionType, ElementNode node, IXmlLineInfo lineInfo, ILContext context)
{
if (parent is null)
return false;
if (collectionType.FullName != "Microsoft.Maui.Controls.ResourceDictionary"
&& !collectionType.InheritsFromOrImplements(context.Cache, context.Module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "ResourceDictionary"))))
return false;
if (node.Properties.TryGetValue(XmlName.xKey, out INode value))
{
var valueNode = value as ValueNode ?? throw new BuildException(XKeyNotLiteral, lineInfo, null);
var key = valueNode.Value as string;
var names = context.Cache.GetResourceNamesInUse(parent);
if (names.Contains(key))
throw new BuildException(ResourceDictDuplicateKey, lineInfo, null, key);
return true;
}
//is there a RD.Add() overrides that accepts this ?
var nodeTypeRef = context.Variables[node].VariableType;
var module = context.Body.Method.Module;
if (module.ImportMethodReference(context.Cache,
module.GetTypeDefinition(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "ResourceDictionary")),
methodName: "Add",
parameterTypes: [nodeTypeRef]) != null)
return true;
throw new BuildException(ResourceDictMissingKey, lineInfo, null);
}
View on GitHub (pinned to f377ff1c5e)
Solutions
- Use a plain string literal for x:Key.
- If you need a shared/constant key, define it as a literal string (e.g. `x:Key="myKey"`).
- Do not place markup extensions or nested elements in x:Key.
Example fix
<!-- before -->
<x:String x:Key="{StaticResource KeyRes}">Hi</x:String>
<!-- after -->
<x:String x:Key="greetingKey">Hi</x:String> Defensive patterns
Strategy: validation
Validate before calling
// x:Key must be a plain string literal; reject any markup/element form
static bool IsLiteralXKey(string raw) => !string.IsNullOrWhiteSpace(raw) && !raw.StartsWith("{"); Prevention
- Always set x:Key to a literal string.
- Never place markup extensions or nested elements in x:Key.
- Keep keys short, stable, and unique within the ResourceDictionary.
When it happens
Trigger: Setting x:Key to a markup extension or nested element, e.g. `x:Key="{StaticResource KeyRes}"` instead of a literal string.
Common situations: Developer tries to indirect the key through a resource or binding; copy-paste of a markup extension into x:Key.
Related errors
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/41570598476cd219.
Report an issue: GitHub.