angular/components · error

Value must be an array in multiple-selection mode.

Error message

Value must be an array in multiple-selection mode.

What it means

MatSelect throws this in dev mode when the form-control value bound to a multi-select (`multiple="true"`) is not an array. `_setSelectionByValue` iterates `value.forEach(...)` for multi-selection, so a non-array value cannot be applied. It is a developer-facing contract error: multi-select values must always be `any[]`.

Source

Thrown at src/material/select/select.ts:1044

        this._value = this.ngControl.value;
      }

      this._setSelectionByValue(this._value);
      this.stateChanges.next();
    });
  }

  /**
   * Sets the selected option based on a value. If no option can be
   * found with the designated value, the select trigger is cleared.
   */
  private _setSelectionByValue(value: any | any[]): void {
    this.options.forEach(option => option.setInactiveStyles());
    this._selectionModel.clear();

    if (this.multiple && value) {
      if (!Array.isArray(value) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
        throw getMatSelectNonArrayValueError();
      }

      value.forEach((currentValue: any) => this._selectOptionByValue(currentValue));
      this._sortValues();
    } else {
      const correspondingOption = this._selectOptionByValue(value);

      // Shift focus to the active item. Note that we shouldn't do this in multiple
      // mode, because we don't know what option the user interacted with last.
      if (correspondingOption) {
        this._keyManager.updateActiveItem(correspondingOption);
      } else if (!this.panelOpen) {
        // Otherwise reset the highlighted option. Note that we only want to do this while
        // closed, because doing it while open can shift the user's focus unnecessarily.
        this._keyManager.updateActiveItem(-1);
      }
    }

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Wrap the bound value in an array (e.g. `this.control.setValue(['foo'])`).
  2. Ensure the `multiple` input is bound statically and not switched after the value is set.
  3. Guard assignments: only pass array values to a multi-select (see validationCode).
  4. If the value comes from a server response, normalize it to an array before assigning.

Example fix

// before
this.cityCtrl = new FormControl('nyc'); // mat-select is multiple
// after
this.cityCtrl = new FormControl(['nyc']);
Defensive patterns

Strategy: validation

Validate before calling

function assertArrayValue(multiple: boolean, value: unknown) {
  if (multiple && !Array.isArray(value)) {
    throw new Error('mat-select multiple requires an array value');
  }
}
// call before assigning: assertArrayValue(true, this.control.value);

Type guard

function isArrayValue(v: unknown): v is any[] { return Array.isArray(v); }

Try / catch

try {
  this.select.value = rawValue as any[];
} catch (e) {
  console.error('mat-select multi value must be an array', e);
  this.select.value = [];
}

Prevention

When it happens

Trigger: Calling `select.value = 'foo'` (or patching a FormControl with a string) on a `<mat-select multiple>`, or `compareWith`/writeValue invoked with a single object while multiple mode is on.

Common situations: Toggling the `multiple` attribute at runtime without converting the existing value from scalar to array; initializing a FormControl with a single item; forgetting `[value]` should be bound as an array in reactive forms.

Related errors


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