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

  1. Wrap VisualState elements in a VisualStateGroup inside the VisualStateGroupList.
  2. Follow the canonical nesting: VisualElement > VisualStateManager.VisualStateGroups > VisualStateGroupList > VisualStateGroup > VisualState > Setter.
  3. 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

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


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