dotnet/maui · error · BuildException

XC0061

XC0061

Error message

Error while parsing markup expression.

What it means

Thrown when MarkupExpressionParser.MatchMarkup cannot recognize the leading token of a markup expression as a valid markup extension name. After confirming the closing brace, the compiler tries to match the extension identifier; failure means the syntax does not start with a known markup name pattern.

Source

Thrown at src/Controls/src/Build.Tasks/ExpandMarkupsVisitor.cs:91

				if (kvp.Value != node)
					continue;
				name = kvp.Key;
				return true;
			}
			return false;
		}

		static INode ParseExpression(ref string expression, ILContext context, IXmlNamespaceResolver nsResolver,
			IXmlLineInfo xmlLineInfo)
		{
			if (expression.StartsWith("{}", StringComparison.Ordinal))
				return new ValueNode(expression.Substring(2), null);

			if (expression[expression.Length - 1] != '}')
				throw new BuildException(BuildExceptionCode.MarkupNotClosed, xmlLineInfo, null);

			if (!MarkupExpressionParser.MatchMarkup(out var match, expression, out var len))
				throw new BuildException(BuildExceptionCode.MarkupParsingFailed, xmlLineInfo, null);
			expression = expression.Substring(len).TrimStart();
			if (expression.Length == 0)
				throw new BuildException(BuildExceptionCode.MarkupNotClosed, xmlLineInfo, null);

			var provider = new XamlServiceProvider(null, null);
			provider.Add(typeof(ILContextProvider), new ILContextProvider(context));
			provider.Add(typeof(IXmlNamespaceResolver), nsResolver);
			provider.Add(typeof(IXmlLineInfoProvider), new XmlLineInfoProvider(xmlLineInfo));

			return new MarkupExpansionParser().Parse(match, ref expression, provider);
		}

		class ILContextProvider(ILContext context)
		{
			public ILContext Context { get; } = context;
		}

		class MarkupExpansionParser : MarkupExpressionParser, IExpressionParser<INode>

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Escape literal braces with the '{} ' prefix, e.g. Content="{}{not a binding}".
  2. If intending a markup extension, start with a valid name: '{Binding ...}', '{x:Static ...}', etc.
  3. Remove stray '{' characters from attribute values.

Example fix

// before
<Label Text="{some literal text}" />
// after
<Label Text="{}{some literal text}" />
Defensive patterns

Strategy: validation

Validate before calling

// Lint: a '{' must be followed by a valid markup name or escaped with '{}'
static readonly Regex MarkupName = new(@"^\{([A-Za-z_][\w\.]*:?[A-Za-z_][\w\.]*)");
static bool MarkupStartsValid(string value) =>
    value.StartsWith("{}") || MarkupName.IsMatch(value) || !value.StartsWith("{");

Prevention

When it happens

Trigger: An expression that begins with '{' but the next token is not a valid markup name (e.g. '{123}' or '{ }'); a malformed/empty markup name; stray '{' used as literal text without the '{}' escape prefix.

Common situations: Using '{' literally in text without escaping with '{}'; whitespace or operators right after '{'; tooling that injects a brace for interpolation.

Related errors


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