dotnet/maui · error · NotSupportedException
DataTemplateSelector.OnSelectTemplate must not return anothe
Error message
DataTemplateSelector.OnSelectTemplate must not return another DataTemplateSelector
What it means
DataTemplateSelector.SelectTemplate calls the overridden OnSelectTemplate and then rejects the result if it is itself a DataTemplateSelector (NotSupportedException). Nested selectors are forbidden because SelectTemplate caches per-type templates and the recycling path assumes a concrete DataTemplate; allowing a selector to return a selector would create unbounded recursion and break caching.
Source
Thrown at src/Controls/src/Core/DataTemplateSelector.cs:34
/// <param name="container">The bindable object that will display the templated item.</param>
/// <returns>The selected <see cref="DataTemplate"/>.</returns>
public DataTemplate SelectTemplate(object item, BindableObject container)
{
#pragma warning disable CS0618 // Type or member is obsolete
var listView = container as ListView;
#pragma warning restore CS0618 // Type or member is obsolete
var recycle = listView == null ? false :
(listView.CachingStrategy & ListViewCachingStrategy.RecycleElementAndDataTemplate) ==
ListViewCachingStrategy.RecycleElementAndDataTemplate;
DataTemplate dataTemplate = null;
if (recycle && _dataTemplates.TryGetValue(item.GetType(), out dataTemplate))
return dataTemplate;
dataTemplate = OnSelectTemplate(item, container);
if (dataTemplate is DataTemplateSelector)
throw new NotSupportedException(
"DataTemplateSelector.OnSelectTemplate must not return another DataTemplateSelector");
if (recycle)
{
if (!dataTemplate.CanRecycle)
throw new NotSupportedException(
"RecycleElementAndDataTemplate requires DataTemplate activated with ctor taking a type.");
_dataTemplates[item.GetType()] = dataTemplate;
}
return dataTemplate;
}
protected abstract DataTemplate OnSelectTemplate(object item, BindableObject container);
}
}View on GitHub (pinned to f377ff1c5e)
Solutions
- Make OnSelectTemplate return a concrete DataTemplate (or null), never a DataTemplateSelector.
- If you want composition, call the inner selector's SelectTemplate (or OnSelectTemplate) inside your override and return the resolved DataTemplate it yields.
- Cache concrete DataTemplate instances as fields and return those.
Example fix
// before
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
=> item is TypeA ? _otherSelector : _templateB; // _otherSelector is a DataTemplateSelector -> throws
// after
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
=> item is TypeA ? _otherSelector.SelectTemplate(item, container) : _templateB; Defensive patterns
Strategy: validation
Validate before calling
// Guard OnSelectTemplate implementations to never return a selector.
static DataTemplate SafeSelect(DataTemplate result)
{
if (result is DataTemplateSelector)
throw new ArgumentException("OnSelectTemplate returned a DataTemplateSelector; resolve to a concrete DataTemplate first.");
return result;
} Type guard
static bool IsConcreteDataTemplate(DataTemplate t) => t is not DataTemplateSelector;
Prevention
- Make SelectTemplate/OnSelectTemplate return cached concrete DataTemplate fields.
- When composing selectors, call SelectTemplate on the inner selector and return its resolved template.
- Add a unit test asserting every branch of OnSelectTemplate returns a non-selector DataTemplate.
When it happens
Trigger: A custom DataTemplateSelector whose OnSelectTemplate returns an instance of another DataTemplateSelector subclass; delegating selection to a composed selector and returning that selector object rather than its resolved DataTemplate.
Common situations: Refactoring a single large selector into multiple selectors and accidentally returning the sub-selector; intent to compose selection logic by chaining selectors.
Related errors
- ItemTemplate count has exceeded the limit of {ViewTypeCount}
- RecycleElementAndDataTemplate requires DataTemplate activate
- ItemTemplate count has exceeded the limit of {ViewTypeCount}
- The Map.ItemTemplate property only supports DataTemplate. Se
- You are using an instance of {nameof(DataTemplateSelector)}
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/119bfdb7b3171970.
Report an issue: GitHub.