{"record":{"id":"119bfdb7b3171970","repo":"dotnet/maui","slug":"datatemplateselector-onselecttemplate-must-not-ret","errorCode":null,"errorMessage":"DataTemplateSelector.OnSelectTemplate must not return another DataTemplateSelector","messagePattern":"DataTemplateSelector\\.OnSelectTemplate must not return another DataTemplateSelector","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Controls/src/Core/DataTemplateSelector.cs","lineNumber":34,"sourceCode":"\t\t/// <param name=\"container\">The bindable object that will display the templated item.</param>\n\t\t/// <returns>The selected <see cref=\"DataTemplate\"/>.</returns>\n\t\tpublic DataTemplate SelectTemplate(object item, BindableObject container)\n\t\t{\n#pragma warning disable CS0618 // Type or member is obsolete\n\t\t\tvar listView = container as ListView;\n#pragma warning restore CS0618 // Type or member is obsolete\n\n\t\t\tvar recycle = listView == null ? false :\n\t\t\t\t(listView.CachingStrategy & ListViewCachingStrategy.RecycleElementAndDataTemplate) ==\n\t\t\t\t\tListViewCachingStrategy.RecycleElementAndDataTemplate;\n\n\t\t\tDataTemplate dataTemplate = null;\n\t\t\tif (recycle && _dataTemplates.TryGetValue(item.GetType(), out dataTemplate))\n\t\t\t\treturn dataTemplate;\n\n\t\t\tdataTemplate = OnSelectTemplate(item, container);\n\t\t\tif (dataTemplate is DataTemplateSelector)\n\t\t\t\tthrow new NotSupportedException(\n\t\t\t\t\t\"DataTemplateSelector.OnSelectTemplate must not return another DataTemplateSelector\");\n\n\t\t\tif (recycle)\n\t\t\t{\n\t\t\t\tif (!dataTemplate.CanRecycle)\n\t\t\t\t\tthrow new NotSupportedException(\n\t\t\t\t\t\t\"RecycleElementAndDataTemplate requires DataTemplate activated with ctor taking a type.\");\n\n\t\t\t\t_dataTemplates[item.GetType()] = dataTemplate;\n\t\t\t}\n\n\t\t\treturn dataTemplate;\n\t\t}\n\n\t\tprotected abstract DataTemplate OnSelectTemplate(object item, BindableObject container);\n\t}\n}","sourceCodeStart":16,"sourceCodeEnd":51,"githubUrl":"https://github.com/dotnet/maui/blob/f377ff1c5ee04d334d8a925f50c83a6b7afddf03/src/Controls/src/Core/DataTemplateSelector.cs#L16-L51","documentation":"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.","triggerScenarios":"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.","commonSituations":"Refactoring a single large selector into multiple selectors and accidentally returning the sub-selector; intent to compose selection logic by chaining selectors.","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."],"exampleFix":"// before\nprotected override DataTemplate OnSelectTemplate(object item, BindableObject container)\n    => item is TypeA ? _otherSelector : _templateB; // _otherSelector is a DataTemplateSelector -> throws\n\n// after\nprotected override DataTemplate OnSelectTemplate(object item, BindableObject container)\n    => item is TypeA ? _otherSelector.SelectTemplate(item, container) : _templateB;","handlingStrategy":"validation","validationCode":"// Guard OnSelectTemplate implementations to never return a selector.\nstatic DataTemplate SafeSelect(DataTemplate result)\n{\n    if (result is DataTemplateSelector)\n        throw new ArgumentException(\"OnSelectTemplate returned a DataTemplateSelector; resolve to a concrete DataTemplate first.\");\n    return result;\n}","typeGuard":"static bool IsConcreteDataTemplate(DataTemplate t) => t is not DataTemplateSelector;","tryCatchPattern":null,"preventionTips":["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."],"tags":["datatemplateselector","datatemplate","listview","notsupported"],"backgroundTag":null,"analyzedSha":"f377ff1c5ee04d334d8a925f50c83a6b7afddf03","analyzedAt":"2026-08-13T14:26:18.069Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}