AvaloniaUI/Avalonia · error · InvalidOperationException
ControlTemplate styles cannot contain multiple template sele
Error message
ControlTemplate styles cannot contain multiple template selectors.
What it means
Thrown during ValidateNestingSelector when a selector chain inside a ControlTheme contains more than one TemplateSelector. A ControlTheme can only enter its control's template once; chaining multiple `:template()` steps is structurally invalid because there is no nested template to enter.
Source
Thrown at src/Avalonia.Base/Styling/Selector.cs:121
/// </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);
}
}
private static SelectorMatch MatchUntilCombinator(
StyledElement control,View on GitHub (pinned to 11c5427268)
Solutions
- Use exactly one Template selector per ControlTheme selector chain; address deeper parts with child/descendant combinators after the single `:template()`.
- If you need to style a nested templated control, define a separate ControlTheme for that control type instead of chaining template selectors.
Example fix
// before (two template selectors) new Style(s => s.OfType<Button>().Template().OfType<ContentPresenter>().Template().OfType<TextBlock>()) // after (single template, then descendant) new Style(s => s.OfType<Button>().Template().Descendant().OfType<TextBlock>())
Defensive patterns
Strategy: validation
Validate before calling
// Count Template selectors in the chain; reject if > 1 before assigning.
int CountTemplates(Selector? s)
{
int n = 0;
while (s is not null) { if (s is TemplateSelector) n++; s = s.MoveNextPrevious(); }
return n;
} Prevention
- Use at most one `:template()` per ControlTheme selector chain.
- For nested templated controls, author a separate ControlTheme.
- Lint selectors for duplicate Template tokens.
When it happens
Trigger: Writing a selector like `Button /template/ ContentPresenter /template/ TextBlock` inside a ControlTheme. The counter increments on the first TemplateSelector and the second triggers the throw.
Common situations: Assuming template parts have their own templates that can be re-entered; copy-pasting a template selector segment; building selectors programmatically and concatenating two Template() calls.
Related errors
- ControlTheme style may not directly contain a child or desce
- Invalid selector: Template selector must be followed by cont
- Need more than one query to OR.
- Need more than one selector to OR.
- Child styles must have a nesting selector.
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/a65f3bab8342859d.
Report an issue: GitHub.