angular/components · error · Error
Unknown data source
Error message
Unknown data source
What it means
CdkSelection._observeRenderChanges resolves its data source as a stream: a Connect/Observable input, or an array wrapped with observableOf. If _dataSource is neither (null, undefined, or an unsupported type like a plain object), the dev-mode check throws 'Unknown data source' before subscribing, because there is no way to obtain the data stream.
Source
Thrown at src/cdk-experimental/selection/selection.ts:107
}
private _observeRenderChanges() {
if (!this._dataSource) {
return;
}
let dataStream: Observable<readonly T[]> | undefined;
if (isDataSource(this._dataSource)) {
dataStream = this._dataSource.connect(this);
} else if (this._dataSource instanceof Observable) {
dataStream = this._dataSource;
} else if (Array.isArray(this._dataSource)) {
dataStream = observableOf(this._dataSource);
}
if (dataStream == null && (typeof ngDevMode === 'undefined' || ngDevMode)) {
throw Error('Unknown data source');
}
this._renderChangeSubscription = dataStream!
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this._data = data || [];
});
}
ngOnInit() {
this._selection = new SelectionSet<T>(this._multiple, this.trackByFn);
this._selection.changed.pipe(takeUntil(this._destroyed)).subscribe(change => {
this._updateSelectAllState();
this.change.emit(change);
});
}
ngAfterContentChecked() {View on GitHub (pinned to 0411926e7d)
Solutions
- Pass an array: [dataSource]="items" — it will be wrapped in of(items) automatically.
- Or pass a stream (Observable/Connect) that emits arrays, holding a default of [] until data arrives: items$ = http$.pipe(startWith([])).
- Initialize the bound property to [] rather than undefined while loading.
Example fix
// before @Input() dataSource; // undefined until fetch resolves // after items: T[] = []; this.api.load().subscribe(d => this.items = d); <cdk-selection [dataSource]="items">
Defensive patterns
Strategy: validation
Validate before calling
function isValidDataSource(src: unknown): src is readonly unknown[] | Observable<unknown[]> {
return Array.isArray(src) || (src instanceof Observable);
}
if (!isValidDataSource(this.dataSource)) throw new Error('CdkSelection dataSource must be an array or Observable'); Type guard
function isSelectableDataSource<T>(src: unknown): src is T[] | Observable<T[]> {
return Array.isArray(src) || src instanceof Observable;
} Try / catch
try {
selection.dataSource = maybeSource;
cdr.detectChanges();
} catch (e) {
if ((e as Error).message === 'Unknown data source') {
selection.dataSource = [];
} else throw e;
} Prevention
- Initialize dataSource-bound properties to [] instead of null/undefined.
- Only pass arrays or Observables — never MatTableDataSource or plain objects.
- Use startWith([]) on async streams so a value exists before first check.
When it happens
Trigger: Binding [dataSource] to null/undefined (e.g., async data that has not resolved yet); passing a plain non-array object; assigning an incompatible type after a refactor; forgetting the dataSource input entirely.
Common situations: Data loaded asynchronously so the property is undefined on first render before ngAfterContentChecked; migrating from MatTableDataSource which CdkSelection does not understand; server responses typed as object instead of array.
Related errors
- SelectionSet: not multiple selection
- SelectionSet: index required when trackByFn is used.
- CdkSelectAll: missing CdkSelection in the parent
- CdkSelection: index required when trackBy is used
- CdkSelection: multiple selection not enabled
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/779b21f6f1bee8da.
Report an issue: GitHub.