{"record":{"id":"cea3b7c3e464e24b","repo":"Unity-Technologies/UnityCsReference","slug":"treeview-rootitem-children-null-did-you-for","errorCode":null,"errorMessage":"TreeView: 'rootItem.children == null'. Did you forget to add children? If you intend to only create the list of rows (not the full tree) then you need to override: BuildRows, GetAncestors and GetDescendantsThatHaveChildren.","messagePattern":"TreeView: 'rootItem\\.children == null'\\. Did you forget to add children\\? If you intend to only create the list of rows \\(not the full tree\\) then you need to override: BuildRows, GetAncestors and GetDescendantsThatHaveChildren\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"critical","filePath":"Editor/Mono/GUI/TreeView/TreeViewControl/TreeViewControlDataSource.cs","lineNumber":45,"sourceCode":"                // Clear root item to ensure client gets a call to BuildRoot every time Reload is called\n                m_RootItem = null;\n                base.ReloadData();\n            }\n\n            void ValidateRootItem()\n            {\n                if (m_RootItem == null)\n                {\n                    throw new NullReferenceException(\"BuildRoot should set a valid root item.\");\n                }\n                if (m_RootItem.depth != -1)\n                {\n                    Debug.LogError(\"BuildRoot should ensure the root item has a depth == -1. The visible items start at depth == 0.\");\n                    m_RootItem.depth = -1;\n                }\n                if (m_RootItem.children == null && !m_Owner.m_OverriddenMethods.hasBuildRows)\n                {\n                    throw new InvalidOperationException(\"TreeView: 'rootItem.children == null'. Did you forget to add children? If you intend to only create the list of rows (not the full tree) then you need to override: BuildRows, GetAncestors and GetDescendantsThatHaveChildren.\");\n                }\n            }\n\n            public override void FetchData()\n            {\n                // Set before BuildRoot and BuildRows so we can call GetRows in them without recursion\n                m_NeedRefreshRows = false;\n\n                // Root\n                if (m_RootItem == null)\n                {\n                    m_RootItem = m_Owner.BuildRoot();\n                    ValidateRootItem();\n                }\n\n                // Rows\n                m_Rows = m_Owner.BuildRows(m_RootItem);\n                if (m_Rows == null)","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/Unity-Technologies/UnityCsReference/blob/225b0fbdb57cc17d094e8056b71f8314aba56f73/Editor/Mono/GUI/TreeView/TreeViewControl/TreeViewControlDataSource.cs#L27-L63","documentation":"Thrown by ValidateRootItem when rootItem.children is null AND the subclass has not overridden BuildRows. Unity's TreeView can operate in two modes: full-tree (BuildRoot populates children) or rows-only (override BuildRows/GetAncestors/GetDescendantsThatHaveChildren). Having null children without the rows-only overrides is an inconsistent configuration.","triggerScenarios":"Overriding BuildRoot to return a root with children == null (default) without also overriding BuildRows, GetAncestors, and GetDescendantsThatHaveChildren; switching from full-tree to rows-only mode but forgetting the required overrides.","commonSituations":"Building a lazy-loaded TreeView that only computes visible rows; a data source where the root legitimately has no children yet but BuildRows was not overridden.","solutions":["If you want full-tree mode: ensure BuildRoot sets root.children (call AddChild or ensure children list is populated, even if empty).","If you want rows-only mode: override BuildRows, GetAncestors, and GetDescendantsThatHaveChildren in your subclass.","Initialize root.children to an empty list rather than leaving it null: root.children = new List<TreeViewItem<TIdentifier>>();"],"exampleFix":"// before\nprotected override TreeViewItem<int> BuildRoot()\n{\n    return new TreeViewItem<int>(0, -1, \"root\"); // children null\n}\n\n// after (full-tree mode)\nprotected override TreeViewItem<int> BuildRoot()\n{\n    var root = new TreeViewItem<int>(0, -1, \"root\");\n    root.children = new List<TreeViewItem<int>>();\n    // add children...\n    return root;\n}","handlingStrategy":"validation","validationCode":"var root = new TreeViewItem<int>(0, -1, \"root\");\nroot.children = new List<TreeViewItem<int>>(); // never null\nreturn root;","typeGuard":"static bool HasConsistentChildren<T>(TreeViewItem<T> root, bool hasBuildRows)\n    => root.children != null || hasBuildRows;","tryCatchPattern":null,"preventionTips":["Always set root.children to at least an empty list in full-tree mode.","If using rows-only mode, override BuildRows, GetAncestors, and GetDescendantsThatHaveChildren.","Decide on tree vs rows-only mode early and implement the required overrides."],"tags":["unity","treeview","buildroot","buildrows","configuration"],"backgroundTag":null,"analyzedSha":"225b0fbdb57cc17d094e8056b71f8314aba56f73","analyzedAt":"2026-08-13T19:07:19.849Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}