dotnet/maui · error · XamlParseException

Expected {nameof(VisualStateGroupList)} but found {parents[3

Error message

Expected {nameof(VisualStateGroupList)} but found {parents[3]}.

What it means

XamlParseException raised in FindTypeForVisualState when parents[3] (after the VisualStateGroup was confirmed) is neither a VisualElement (direct visual states) nor a VisualStateGroupList. The only two valid containers for a VisualStateGroup are a VisualStateGroupList (under a Style) or a VisualElement directly; anything else is a structural error.

Source

Thrown at src/Controls/src/Core/BindablePropertyConverter.cs:143

			=> 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 
			if (parents[5] is Style style)
				return style.TargetType;

			throw new XamlParseException($"Unable to find a TragetType for the Bindable Property. Try prefixing it with the TargetType.", lineInfo);

		}

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. If the group lives under a Style, wrap it in a VisualStateGroupList.
  2. If it lives directly on an element, ensure that element is a VisualElement.
  3. Match the documented parent chain for the Style vs direct-element cases.

Example fix

<!-- before -->
<Style><VisualStateGroup> ... </VisualStateGroup></Style>

<!-- after -->
<Style>
  <VisualStateManager.VisualStateGroups>
    <VisualStateGroupList>
      <VisualStateGroup> ... </VisualStateGroup>
    </VisualStateGroupList>
  </VisualStateManager.VisualStateGroups>
</Style>
Defensive patterns

Strategy: validation

Validate before calling

// In a Style, wrap VisualStateGroup in a VisualStateGroupList under
// VisualStateManager.VisualStateGroups.

Try / catch

try { /* compile */ }
catch (XamlParseException ex) when (ex.Message.Contains("VisualStateGroupList"))
{
    // prompt author to add the VisualStateGroupList wrapper
}

Prevention

When it happens

Trigger: Placing a VisualStateGroup under a non-VisualElement and non-VisualStateGroupList parent; a malformed Style whose Setters/VisualStateGroups are mis-nested; custom containers used as visual-state hosts.

Common situations: Editing a Style's VisualStateManager section and dropping the VisualStateGroupList wrapper; putting visual states on a non-visual element.

Related errors


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