angular/components · warning
Tree is using conflicting node types which can cause unexpec
Error message
Tree is using conflicting node types which can cause unexpected behavior. Please use tree nodes of the same type (e.g. only flat or only nested). Current node type: "${currentType}", new node type "${newType}". What it means
A CDK tree can be built with either flat nodes (`cdk-flat-tree`-style, `TreeFlattener`) or nested nodes (recursive `cdk-nested-tree`), but not both at once. `_setNodeTypeIfUnset` records the first node type seen and warns in dev mode when a second, different type appears, because mixing them causes undefined rendering/selection behavior.
Source
Thrown at src/cdk/tree/tree.ts:331
if (defaultNodeDefs.length > 1 && (typeof ngDevMode === 'undefined' || ngDevMode)) {
throw getTreeMultipleDefaultNodeDefsError();
}
this._defaultNodeDef = defaultNodeDefs[0];
}
/**
* Sets the node type for the tree, if it hasn't been set yet.
*
* This will be called by the first node that's rendered in order for the tree
* to determine what data transformations are required.
*/
_setNodeTypeIfUnset(newType: 'flat' | 'nested') {
const currentType = this._nodeType.value;
if (currentType === null) {
this._nodeType.next(newType);
} else if ((typeof ngDevMode === 'undefined' || ngDevMode) && currentType !== newType) {
console.warn(
`Tree is using conflicting node types which can cause unexpected behavior. ` +
`Please use tree nodes of the same type (e.g. only flat or only nested). ` +
`Current node type: "${currentType}", new node type "${newType}".`,
);
}
}
/**
* Switch to the provided data source by resetting the data and unsubscribing from the current
* render change subscription if one exists. If the data source is null, interpret this by
* clearing the node outlet. Otherwise start listening for new data.
*/
private _switchDataSource(dataSource: DataSource<T> | Observable<T[]> | T[]) {
if (this._dataSource && typeof (this._dataSource as DataSource<T>).disconnect === 'function') {
(this.dataSource as DataSource<T>).disconnect(this);
}
this._dataSubscription?.unsubscribe();View on GitHub (pinned to 0411926e7d)
Solutions
- Use only one node type per tree: all `<mat-tree-node>` for flat trees, all `<mat-nested-tree-node>` for nested trees.
- Delete leftover templates of the other node type from the tree's template.
- If you need both forms, render two separate `mat-tree` components.
Example fix
<!-- before -->
<mat-tree [dataSource]="dataSource">
<mat-tree-node *matTreeNodeDef="let node">{{node.name}}</mat-tree-node>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">...</mat-nested-tree-node>
</mat-tree>
<!-- after (nested tree) -->
<mat-tree [dataSource]="dataSource">
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">...</mat-nested-tree-node>
</mat-tree> Defensive patterns
Strategy: validation
Validate before calling
// audit tree templates in CI
const flat = /<(mat|cdk)-tree-node/.test(tpl);
const nested = /<(mat|cdk)-nested-tree-node/.test(tpl);
if (flat && nested) throw new Error('Mixed tree node types in ' + file); Prevention
- Pick flat or nested tree style per component and document it.
- Keep one node template per tree; delete unused alternates.
- Run dev-mode builds locally — this warning only appears when ngDevMode is active.
When it happens
Trigger: Declaring `mat-tree` children that mix `<mat-tree-node>` (flat) with `<mat-nested-tree-node>` (nested), or conditionally rendering both node kinds in the same tree template.
Common situations: Refactoring a flat tree to nested (or vice versa) and leaving old node templates in place; copying node templates between trees; dynamic template switches based on data.
Related errors
- Incorrect tree structure containing detached node.
- ListKeyManager constructed with a signal must receive an inj
- KeyManager items in typeahead mode must implement the `getLa
- CdkDropList could not find an element container matching the
- Invalid DOM structure for drop list. Alternate container ele
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/0acfabdf72f7dbec.
Report an issue: GitHub.