dotnet/maui · error · XamlParseException
Expected VisualStateGroup but found {parent.Parent}
Error message
Expected VisualStateGroup but found {parent.Parent} What it means
A XamlParseException from FindTypeNameForVisualState. When resolving a single-name property inside a VisualState, the converter walks up the XAML tree to find the owning type and requires the VisualState's direct parent to be a VisualStateGroup. If that parent is any other element, it throws 'Expected VisualStateGroup but found ...'.
Source
Thrown at src/Controls/src/Build.Tasks/CompiledConverters/BindablePropertyConverter.cs:89
if (bpRef == null)
throw new BuildException(PropertyResolution, node, null, propertyName, typeRef.Name);
return bpRef;
static XmlType GetTargetTypeName(INode node)
{
var targetType = ((node as ElementNode).Properties[new XmlName("", "TargetType")] as ValueNode)?.Value as string;
return TypeArgumentsParser.ParseSingle(targetType, node.NamespaceResolver, (IXmlLineInfo)node);
}
}
static XmlType FindTypeNameForVisualState(ElementNode parent, IXmlLineInfo lineInfo, ILContext context)
{
//1. parent is VisualState, don't check that
//2. check that the VS is in a VSG
// if (!(parent.Parent is IElementNode target) || target.XmlType.NamespaceUri != XamlParser.MauiUri || target.XmlType.Name != nameof(VisualStateGroup))
if (parent.Parent is not ElementNode target || !target.XmlType.IsOfAnyType(nameof(VisualStateGroup)))
throw new XamlParseException($"Expected {nameof(VisualStateGroup)} but found {parent.Parent}", lineInfo);
//3. if the VSG is in a VSGL, skip that as it could be implicit
if ( target.Parent is ListNode
|| target.Parent is ElementNode { XmlType: XmlType xt } && xt.IsOfAnyType(nameof(VisualStateGroupList)))
target = target.Parent.Parent as ElementNode;
else
target = target.Parent as ElementNode;
//4. target is now a Setter in a Style, or a VE
if (target.XmlType.IsOfAnyType(nameof(Setter)))
{
var targetType = ((target?.Parent as ElementNode)?.Properties[new XmlName("", "TargetType")] as ValueNode)?.Value as string;
return TypeArgumentsParser.ParseSingle(targetType, parent.NamespaceResolver, lineInfo);
}
else
return target.XmlType;
}
View on GitHub (pinned to f377ff1c5e)
Solutions
- Wrap <VisualState> elements inside a <VisualStateGroup>, which itself goes inside a <VisualStateGroupList> under VisualStateManager.VisualStates.
- Validate the nesting order: control > VisualStateManager.VisualStates > VisualStateGroupList > VisualStateGroup > VisualState > Setter.
Example fix
<!-- before -->
<VisualStateManager.VisualStates>
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateManager.VisualStates>
<!-- after -->
<VisualStateManager.VisualStates>
<VisualStateGroup>
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStates> Defensive patterns
Strategy: validation
Prevention
- Always nest VisualState inside a VisualStateGroup (and that inside VisualStateGroupList).
- Memorize the hierarchy: VisualStateManager.VisualStates > VisualStateGroupList > VisualStateGroup > VisualState > Setter.
- Use XAML templates/snippets for VisualStateManager blocks to avoid mis-nesting.
When it happens
Trigger: A <VisualState> element is placed directly inside something other than a <VisualStateGroup> — e.g. directly under a VisualStateManager, a Style, or a control — so the parent check fails.
Common situations: Omitting the VisualStateGroup wrapper; mis-nesting VisualState inside VisualStateGroupList without the intermediate group; structural typo in a VisualStateManager block.
Related errors
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/d8a8a8bd2a565d89.
Report an issue: GitHub.