dotnet/maui · error · XamlParseException
Expected {nameof(VisualStateGroup)} but found {parents[2]}.
Error message
Expected {nameof(VisualStateGroup)} but found {parents[2]}. What it means
XamlParseException raised inside FindTypeForVisualState while resolving the target type for a Setter.Property inside a VisualState. The method assumes VisualStates live inside a VisualStateGroup; parents[2] (the grandparent of the Setter's value context) is expected to be a VisualStateGroup, and if it is anything else the XAML structure is wrong.
Source
Thrown at src/Controls/src/Core/BindablePropertyConverter.cs:136
static Type GetControlType(string typeName)
=> Type.GetType("Microsoft.Maui.Controls." + typeName);
[UnconditionalSuppressMessage("TrimAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "The converter is only used when parsing XAML at runtime. The developer will receive a warning " +
"saying that parsing XAML at runtime may not work as expected when trimming.")]
static FieldInfo GetPropertyField(Type type, string fieldName)
=> type.GetField(fieldName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
Type FindTypeForVisualState(IProvideParentValues parentValueProvider, IXmlLineInfo lineInfo)
{
var parents = parentValueProvider.ParentObjects.ToList();
// Skip 0; we would not be making this check if TargetObject were not a Setter
// Skip 1; we would not be making this check if the immediate parent were not a VisualState
// VisualStates must be in a VisualStateGroup
if (parents[2] is not VisualStateGroup)
throw new XamlParseException($"Expected {nameof(VisualStateGroup)} but found {parents[2]}.", lineInfo);
// Are these Visual States directly on a VisualElement?
if (parents[3] is VisualElement vsTarget)
return vsTarget.GetType();
if (parents[3] is not VisualStateGroupList)
throw new XamlParseException($"Expected {nameof(VisualStateGroupList)} but found {parents[3]}.", lineInfo);
if (parents[4] is VisualElement veTarget)
return veTarget.GetType();
if (parents[4] is not Setter)
throw new XamlParseException($"Expected {nameof(Setter)} but found {parents[4]}.", lineInfo);
if (parents[5] is TriggerBase trigger)
return trigger.TargetType;
// These must be part of a Style; verify that View on GitHub (pinned to f377ff1c5e)
Solutions
- Wrap VisualState elements in a VisualStateGroup inside the VisualStateGroupList.
- Follow the canonical nesting: VisualElement > VisualStateManager.VisualStateGroups > VisualStateGroupList > VisualStateGroup > VisualState > Setter.
- Validate the XAML against the documented VisualStateManager structure.
Example fix
<!-- before -->
<VisualStateManager.VisualStateGroups>
<VisualState x:Name="Foo"> ... </VisualState>
</VisualStateManager.VisualStateGroups>
<!-- after -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Foo"> ... </VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups> Defensive patterns
Strategy: validation
Validate before calling
// Use a known-good VisualStateManager template so the parent chain is correct: // VisualStateManager.VisualStateGroups > VisualStateGroupList > VisualStateGroup > VisualState > Setter
Try / catch
try { /* compile XAML */ }
catch (XamlParseException ex) when (ex.Message.Contains("VisualStateGroup"))
{
// point the author at the required nesting level
} Prevention
- Always wrap VisualState in a VisualStateGroup.
- Start visual-state markup from the documented template.
When it happens
Trigger: Placing a VisualState directly under an element without a wrapping VisualStateGroup, or nesting VisualState inside a non-group parent; malformed visual-state markup where a VisualStateGroup is missing.
Common situations: Hand-editing VisualStateManager XAML and forgetting the VisualStateGroup level; tool-generated visual states that skip the group; copy-paste that dropped the group element.
Related errors
- Expected {nameof(VisualStateGroupList)} but found {parents[3
- Expected {nameof(Setter)} but found {parents[4]}.
- Unable to find a TragetType for the Bindable Property. Try p
- Can't resolve {0}
- Can't resolve {parts[0]}
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/c781a18fb31a6c03.
Report an issue: GitHub.