Prerequisites
Ionic Framework Version
v9.x
Current Behavior
While optimizing page loading in my Ionic React app, I started seeing intermittent uncaught exceptions during registration and onboarding in Playwright.
Astra analysis:
Unmounting an IonRouterOutlet with ionPage before its deferred initialization callback runs causes an uncaught exception:
TypeError: Cannot read properties of null (reading 'classList')
at http://localhost:5173/node_modules/.vite/deps/chunk-K6ONCLJS.js?v=7fa17f37:13510:19
at http://localhost:5173/node_modules/.vite/deps/chunk-ANOI66QA.js?v=7fa17f37:35:75
The first frame is the componentOnReady callback in OutletPageManager.componentDidMount().
The reproduction mounts the outlet, then removes it in the parent component's layout effect. This makes the problematic lifecycle ordering deterministic: the child's componentDidMount schedules initialization before the parent's layout effect removes it. No framework internals are mocked or patched, and no timers or network throttling are needed.
Expected Behavior
If the outlet is unmounted before initialization completes, the pending callback should exit without accessing the cleared ref, changing page classes, or registering a stale outlet. No uncaught error should occur.
Steps to Reproduce
-
Clone the reproduction and install dependencies:
git clone --branch outletPageManager https://github.com/ptmkenny/ionic-react-router-6-test.git
cd ionic-react-router-6-test
npm install
npm run dev
-
Open the URL printed by Vite, normally http://localhost:5173/.
-
Click Mount and unmount outlet.
-
Observe Attempts: 1, Uncaught errors: 1, and the classList TypeError printed on the page and in the console.
-
Click again. Each click mounts and removes a new outlet and adds another error. Expected: the error counter remains zero.
Code Reproduction URL
https://github.com/ptmkenny/ionic-react-router-6-test/tree/outletPageManager
Ionic Info
Ionic:
Ionic CLI : 7.2.1 (/home/node/.npm/_npx/f6fddb685269761d/node_modules/@ionic/cli)
Ionic Framework : @ionic/react 9.0.6
Capacitor:
Capacitor CLI : 8.0.0
@capacitor/android : not installed
@capacitor/core : 8.0.0
@capacitor/ios : not installed
Utility:
cordova-res : not installed globally
native-run : 2.0.1
System:
NodeJS : v26.10.0 (/usr/local/bin/node)
npm : 11.19.1
OS : Linux 6.18
Additional Information
From Astra:
Root cause
In OutletPageManager.tsx, componentDidMount() checks this.ionRouterOutlet before scheduling componentOnReady. The callback later reads this.ionRouterOutlet! again and immediately accesses el.classList. React can clear the ref between scheduling and execution. The non-null assertion does not prevent runtime null access.
The same unsafe callback exists in upstream main at 643584b3ac (2026-10-01). A check made only before scheduling is insufficient. The callback must also belong to the current mount and outlet when it executes.
Prerequisites
Ionic Framework Version
v9.x
Current Behavior
While optimizing page loading in my Ionic React app, I started seeing intermittent uncaught exceptions during registration and onboarding in Playwright.
Astra analysis:
Unmounting an
IonRouterOutletwithionPagebefore its deferred initialization callback runs causes an uncaught exception:The first frame is the
componentOnReadycallback inOutletPageManager.componentDidMount().The reproduction mounts the outlet, then removes it in the parent component's layout effect. This makes the problematic lifecycle ordering deterministic: the child's
componentDidMountschedules initialization before the parent's layout effect removes it. No framework internals are mocked or patched, and no timers or network throttling are needed.Expected Behavior
If the outlet is unmounted before initialization completes, the pending callback should exit without accessing the cleared ref, changing page classes, or registering a stale outlet. No uncaught error should occur.
Steps to Reproduce
Clone the reproduction and install dependencies:
git clone --branch outletPageManager https://github.com/ptmkenny/ionic-react-router-6-test.git cd ionic-react-router-6-test npm install npm run devOpen the URL printed by Vite, normally
http://localhost:5173/.Click Mount and unmount outlet.
Observe Attempts: 1, Uncaught errors: 1, and the
classListTypeError printed on the page and in the console.Click again. Each click mounts and removes a new outlet and adds another error. Expected: the error counter remains zero.
Code Reproduction URL
https://github.com/ptmkenny/ionic-react-router-6-test/tree/outletPageManager
Ionic Info
Additional Information
From Astra:
Root cause
In
OutletPageManager.tsx,componentDidMount()checksthis.ionRouterOutletbefore schedulingcomponentOnReady. The callback later readsthis.ionRouterOutlet!again and immediately accessesel.classList. React can clear the ref between scheduling and execution. The non-null assertion does not prevent runtime null access.The same unsafe callback exists in upstream
mainat643584b3ac(2026-10-01). A check made only before scheduling is insufficient. The callback must also belong to the current mount and outlet when it executes.