AvaloniaUI/Avalonia · error · InvalidOperationException
ControlTheme style may not directly contain a child or desce
Error message
ControlTheme style may not directly contain a child or descendent selector.
What it means
Thrown during ValidateNestingSelector when a selector chain belonging to a style nested in a ControlTheme contains a child (`>`) or descendant combinator outside of a `:template()` scope. ControlThemes target a single control instance, so relating to children/descendants of that control is only meaningful after entering the control's template via the Template selector.
Source
Thrown at src/Avalonia.Base/Styling/Selector.cs:118
/// <summary>
/// Moves to the previous selector.
/// </summary>
private protected abstract Selector? MovePrevious();
/// <summary>
/// Moves to the previous selector or the parent selector.
/// </summary>
private protected abstract Selector? MovePreviousOrParent();
internal virtual void ValidateNestingSelector(bool inControlTheme, int templateCount = 0)
{
var s = this;
if (inControlTheme)
{
if (!s.InTemplate && s.IsCombinator)
throw new InvalidOperationException(
"ControlTheme style may not directly contain a child or descendent selector.");
if (s is TemplateSelector && templateCount++ > 0)
throw new InvalidOperationException(
"ControlTemplate styles cannot contain multiple template selectors.");
}
var previous = s.MovePreviousOrParent();
if (previous is null)
{
if (s is not NestingSelector)
throw new InvalidOperationException("Child styles must have a nesting selector.");
}
else
{
previous.ValidateNestingSelector(inControlTheme, templateCount);
}
}View on GitHub (pinned to 11c5427268)
Solutions
- Add a Template selector step before the combinator, e.g. `Button /template/ ContentPresenter > TextBlock`.
- Move child/descendant rules that target arbitrary visual-tree nodes out of the ControlTheme into an application-level Style.
- Re-read the selector chain and ensure every combinator is preceded by `:template()` when inside a ControlTheme.
Example fix
// before (inside ControlTheme, invalid) new Style(s => s.OfType<Button>().Child().OfType<ContentPresenter>()) // after (enter template first) new Style(s => s.OfType<Button>().Template().OfType<ContentPresenter>())
Defensive patterns
Strategy: validation
Validate before calling
// Ensure every combinator in a ControlTheme selector is preceded by a Template step.
static bool SelectorValidForTheme(Selector s)
{
// Walk the chain; combinators are only allowed after InTemplate becomes true.
return true; // implement per-chain walk using InTemplate/IsCombinator Prevention
- Inside ControlThemes, always address template parts via `:template()` before any `>` or descendant combinator.
- Review theme selectors for stray child/descendant combinators.
- Keep application-level child/descendant rules in app Styles, not ControlThemes.
When it happens
Trigger: Defining a ControlTheme child style with a selector like `Button > ContentPresenter` or `^ TextBlock` (descendant) without first traversing `:template()`. The check fires when `!InTemplate && IsCombinator` while inControlTheme is true.
Common situations: Writing theme styles that try to reach into the visual tree the way application-level Styles do; forgetting to add `/template/ ` before addressing template parts; converting an app Style to a ControlTheme without adjusting combinators.
Related errors
- ControlTemplate styles cannot contain multiple template sele
- Invalid selector: Template selector must be followed by cont
- Nesting selector was specified but cannot determine parent s
- Not selector must have a selector argument.
- Need more than one query to OR.
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/5ef94081c5c1ec8d.
Report an issue: GitHub.