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

  1. Pass an array: [dataSource]="items" — it will be wrapped in of(items) automatically.
  2. Or pass a stream (Observable/Connect) that emits arrays, holding a default of [] until data arrives: items$ = http$.pipe(startWith([])).
  3. 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

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


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/779b21f6f1bee8da. Report an issue: GitHub.