angular/components · error · Error

SelectionSet: not multiple selection

Error message

SelectionSet: not multiple selection

What it means

SelectionSet.select() throws this dev-mode assertion when more than one item is passed to select() while the SelectionSet was created in single-selection mode (multiple: false). The API guard exists so callers do not silently get a partially-applied multi-select on a set that only tracks one selection. It only fires in development builds (ngDevMode).

Source

Thrown at src/cdk-experimental/selection/selection-set.ts:62

 * on them. Because `trackByFn` requires the index of the item to be passed in, the `index` field is
 * expected to be set when calling `isSelected`, `select` and `deselect`.
 */
export class SelectionSet<T> implements TrackBySelection<T> {
  private _selectionMap = new Map<T | ReturnType<TrackByFunction<T>>, SelectableWithIndex<T>>();
  changed = new Subject<SelectionChange<T>>();

  constructor(
    private _multiple = false,
    private _trackByFn?: TrackByFunction<T>,
  ) {}

  isSelected(value: SelectableWithIndex<T>): boolean {
    return this._selectionMap.has(this._getTrackedByValue(value));
  }

  select(...selects: SelectableWithIndex<T>[]) {
    if (!this._multiple && selects.length > 1 && (typeof ngDevMode === 'undefined' || ngDevMode)) {
      throw Error('SelectionSet: not multiple selection');
    }

    const before = this._getCurrentSelection();

    if (!this._multiple) {
      this._selectionMap.clear();
    }

    const toSelect: SelectableWithIndex<T>[] = [];
    for (const select of selects) {
      if (this.isSelected(select)) {
        continue;
      }

      toSelect.push(select);
      this._markSelected(this._getTrackedByValue(select), select);
    }

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Construct the SelectionSet with { multiple: true } if multi-select is intended.
  2. Otherwise select items one at a time in a loop (each select() call replaces the previous selection in single mode).
  3. Guard the call: only call select when the set is multiple, or slice to a single item.

Example fix

// before
const set = new SelectionSet<string>(); // single mode
set.select(...values);

// after
const set = new SelectionSet<string>({ multiple: true });
set.select(...values);
Defensive patterns

Strategy: validation

Validate before calling

function canSelect(set: SelectionSet<unknown>, items: unknown[]): boolean {
  return set.multiple || items.length <= 1;
}
if (!canSelect(set, values)) throw new Error('Cannot multi-select on a single SelectionSet');
set.select(...values.slice(0, set.multiple ? values.length : 1));

Type guard

function isMultipleSet<T>(s: SelectionSet<T>): s is SelectionSet<T> & { multiple: true } {
  return (s as { multiple?: boolean }).multiple === true;
}

Try / catch

try {
  set.select(...values);
} catch (e) {
  if ((e as Error).message.includes('not multiple selection')) {
    values.forEach(v => set.select(v)); // degrade to sequential
  } else throw e;
}

Prevention

When it happens

Trigger: Calling selectionSet.select(itemA, itemB) (spread of an array, or literal multiple args) on a SelectionSet constructed without multiple: true. Deselect/isSelected with one arg is fine; only select with >1 args on a non-multiple set throws.

Common situations: Refactoring code that used SelectionModel multiple mode to SelectionSet; passing a user-selected array straight into select(...items) while forgetting the `multiple` constructor option; a shared helper that always spreads arrays.

Related errors


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