angular/components · error

A drawer was already declared for 'position="${position}"'

Error message

A drawer was already declared for 'position="${position}"'

What it means

MatDrawerContainer validates its drawers in `_validateDrawers` and throws via `throwMatDuplicatedDrawerError` when two `<mat-drawer>` elements declare the same `position` ('start' or 'end'). Each side of a container may hold at most one drawer. It is a template-configuration error caught immediately at render time.

Source

Thrown at src/material/sidenav/drawer.ts:55

  OnDestroy,
  Output,
  QueryList,
  Renderer2,
  ViewChild,
  ViewEncapsulation,
  DOCUMENT,
  signal,
} from '@angular/core';
import {merge, Observable, Subject} from 'rxjs';
import {debounceTime, delay, filter, map, mapTo, startWith, take, takeUntil} from 'rxjs/operators';
import {_animationsDisabled} from '../core';

/**
 * Throws an exception when two MatDrawer are matching the same position.
 * @docs-private
 */
export function throwMatDuplicatedDrawerError(position: string) {
  throw Error(`A drawer was already declared for 'position="${position}"'`);
}

/** Options for where to set focus to automatically on dialog open */
export type AutoFocusTarget = 'dialog' | 'first-tabbable' | 'first-heading';

/** Result of the toggle promise that indicates the state of the drawer. */
export type MatDrawerToggleResult = 'open' | 'close';

/** Drawer and SideNav display modes. */
export type MatDrawerMode = 'over' | 'push' | 'side';

/** Configures whether drawers should use auto sizing by default. */
export const MAT_DRAWER_DEFAULT_AUTOSIZE = new InjectionToken<boolean>(
  'MAT_DRAWER_DEFAULT_AUTOSIZE',
  {
    providedIn: 'root',
    factory: () => false,
  },

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Give each drawer in the container a unique position: one 'start', one 'end'.
  2. Move the extra drawer into its own `<mat-drawer-container>` if two same-side drawers are needed.
  3. If position is bound with `[position]`, ensure the bound values cannot collide at runtime.
  4. Wrap drawer in `<mat-drawer-content>` usage checks and re-render after fixing the template.

Example fix

// before
<mat-drawer-container>
  <mat-drawer position="start">Menu</mat-drawer>
  <mat-drawer position="start">Filters</mat-drawer>
</mat-drawer-container>
// after
<mat-drawer-container>
  <mat-drawer position="start">Menu</mat-drawer>
  <mat-drawer position="end">Filters</mat-drawer>
</mat-drawer-container>
Defensive patterns

Strategy: validation

Validate before calling

// Template review guard: count drawers per position
const positions = Array.from(
  document.querySelectorAll('mat-drawer')
).map(d => d.getAttribute('ng-reflect-position'));
const dupes = positions.filter((p, i) => positions.indexOf(p) !== i);
if (dupes.length) throw new Error('Duplicate drawer position: ' + dupes[0]);

Prevention

When it happens

Trigger: Declaring two `<mat-drawer position="start">` (or two 'end') inside one `<mat-drawer-container>`, or binding `position` to a property whose value collides with another drawer's.

Common situations: Copy-pasting a drawer block in a template and forgetting to change its position; conditional rendering where two drawers briefly both compute the same position; refactoring from two containers into one.

Related errors


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