Is this a regression?
The previous version in which this bug was not present was
No response
Description
We're seeing errors in production when an app uses SSR with hydration and withEventReplay(). If a user clicks on a mat-select (inside a
mat-form-field) before hydration completes, the click is queued and replayed later, and the replay ends up throwing:
Error: `composedPath` called during event replay.
From what I can tell, Angular core intentionally patches composedPath on replayed events so that it throws, since the composed path is no longer available once browser dispatch is over (see event_dispatcher.ts#prepareEventForReplay).
Meanwhile, the CDK's _getEventTarget helper calls composedPath() unconditionally:
https://github.com/angular/components/blob/main/src/cdk/platform/features/shadow-dom.ts
export function _getEventTarget<T extends EventTarget>(event: Event): T | null {
return (event.composedPath ? event.composedPath()[0] : event.target) as T | null;
}
The error surfaces through MatSelect.onContainerClick, which calls _getEventTarget(event) to check whether the click landed on an option or the overlay backdrop.
Reproduction
Reproduction repo: https://github.com/benjam1337/repro-cdk-composedpath
It's a vanilla ng new --ssr app (Angular 21.2, Material/CDK 21.2.2, live SSR via RenderMode.Server). The only tweaks, detailed in the README, are:
- a
mat-form-field + mat-select in the root component;
- a 20-second artificial delay before client bootstrap in
main.ts, to make
the pre-hydration click window deterministic (in a real app this window
exists on slow devices/networks).
Steps to reproduce:
npm install && npm run build
node dist/repro-cdk-composedpath/server/server.mjs and open http://localhost:4000 with the DevTools console open
- Click on the "Country" select within 20 seconds of page load (before hydration completes)
- Once hydration completes and the click is replayed, the error is thrown
Clicking after hydration works fine, only clicks queued during the pre-hydration window trigger the error.
(I went with a repo rather than StackBlitz because the repro needs the real SSR server + hydration flow, which I couldn't get working reliably there.)
Expected Behavior
The replayed click is handled gracefully and the select opens (or at least fails silently), without an error reaching the application ErrorHandler.
Actual Behavior
Error: `composedPath` called during event replay. is thrown, the replayed click appears to be lost, and the error propagates to the application ErrorHandler (so it gets reported to our error tracking for every affected user).
Environment
- Angular: 21.2.6 (reproduced with 21.2.17 as well)
- CDK/Material: 21.2.2
- Browser(s): observed on Samsung Internet 30 (Android), Chrome Mobile, and others. Seems timing-dependent rather than browser-specific; reproduced locally in Chromium
- Operating System: Android, iOS, Windows, macOS (production traffic); repro on macOS
Is this a regression?
The previous version in which this bug was not present was
No response
Description
We're seeing errors in production when an app uses SSR with hydration and
withEventReplay(). If a user clicks on amat-select(inside amat-form-field) before hydration completes, the click is queued and replayed later, and the replay ends up throwing:From what I can tell, Angular core intentionally patches
composedPathon replayed events so that it throws, since the composed path is no longer available once browser dispatch is over (seeevent_dispatcher.ts#prepareEventForReplay).Meanwhile, the CDK's
_getEventTargethelper callscomposedPath()unconditionally:https://github.com/angular/components/blob/main/src/cdk/platform/features/shadow-dom.ts
The error surfaces through
MatSelect.onContainerClick, which calls_getEventTarget(event)to check whether the click landed on an option or the overlay backdrop.Reproduction
Reproduction repo: https://github.com/benjam1337/repro-cdk-composedpath
It's a vanilla
ng new --ssrapp (Angular 21.2, Material/CDK 21.2.2, live SSR viaRenderMode.Server). The only tweaks, detailed in the README, are:mat-form-field+mat-selectin the root component;main.ts, to makethe pre-hydration click window deterministic (in a real app this window
exists on slow devices/networks).
Steps to reproduce:
npm install && npm run buildnode dist/repro-cdk-composedpath/server/server.mjsand open http://localhost:4000 with the DevTools console openClicking after hydration works fine, only clicks queued during the pre-hydration window trigger the error.
(I went with a repo rather than StackBlitz because the repro needs the real SSR server + hydration flow, which I couldn't get working reliably there.)
Expected Behavior
The replayed click is handled gracefully and the select opens (or at least fails silently), without an error reaching the application
ErrorHandler.Actual Behavior
Error: `composedPath` called during event replay.is thrown, the replayed click appears to be lost, and the error propagates to the applicationErrorHandler(so it gets reported to our error tracking for every affected user).Environment