@asgardeo/react declares react-dom as a direct dependency (pinned to exactly
19.2.4) while react is a peerDependency accepting >=16.8.0. These two cannot
be satisfied together on a React 18 project: npm resolves react to the app's
18.3.1 and installs a second, nested react-dom@19.2.4 beside it. npm reports
the resulting tree as invalid, and both renderers are included in the
production bundle.
Severity note: this does not crash the app. In a minimal repro it renders
correctly under both vite dev and vite preview, with no console errors,
because the SDK's dist/index.js does not itself import react-dom — so the
mismatched copy is never executed. This is a dependency-hygiene and
bundle-size issue rather than a runtime failure, flagging that explicitly
since a crash report would not reproduce. The mismatched copy is, however,
genuinely broken if anything ever loads it directly:
$ node -e "require('./node_modules/@asgardeo/react/node_modules/react-dom/client')"
TypeError: Cannot read properties of undefined (reading 'S')
React 19's react-dom reads
React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, which
React 18.3.1 does not define.
Observed output — npm ls react (tree marked invalid):
asgardeo-react18-repro@0.0.0
+-- @asgardeo/react@0.25.13
| +-- @floating-ui/react@0.27.12
| | +-- @floating-ui/react-dom@2.1.9
| | | -- react@18.3.1 deduped
| | -- react@18.3.1 deduped
| +-- react-dom@19.2.4
| | -- react@18.3.1 deduped invalid: "^19.2.4" from node_modules/@asgardeo/react/node_modules/react-dom
| -- react@18.3.1 deduped
+-- react-dom@18.3.1
`-- react@18.3.1
npm ls react-dom (two copies):
+-- @asgardeo/react@0.25.13
| +-- @floating-ui/react@0.27.12
| | +-- @floating-ui/react-dom@2.1.9
| | | -- react-dom@18.3.1 deduped
| | -- react-dom@19.2.4 deduped
| -- react-dom@19.2.4
-- react-dom@18.3.1
Both renderers reach the production bundle (confirmed by grepping the build
output for each version's internals symbol). Deduplicating them reduces the
bundle from 711,161 to 707,294 bytes (~3.9 kB raw, ~1.3 kB gzip of unused
renderer).
Root cause: react-dom is listed under "dependencies" rather than
"peerDependencies" in @asgardeo/react's package.json:
"dependencies": { "react-dom": "19.2.4", "@types/react-dom": "19.2.3", ... }
"peerDependencies": { "react": ">=16.8.0", "@types/react": ">=16.8.0" }
An exact 19.x pin for the renderer is incompatible with a >=16.8.0 peer range
for react, since react-dom must match the react it renders with.
Suggested fix: move react-dom and @types/react-dom to peerDependencies,
matching how react and @types/react are already handled.
Workaround used: npm overrides pinning the SDK's react-dom to the app's
own version, plus resolve.dedupe: ["react", "react-dom"] in vite.config.js.
Note: adding the override alone had no effect until the lockfile was
regenerated — the existing package-lock.json kept pinning 19.2.4 even after
npm reported the override as applied.
@asgardeo/react declares react-dom as a direct dependency (pinned to exactly
19.2.4) while react is a peerDependency accepting >=16.8.0. These two cannot
be satisfied together on a React 18 project: npm resolves react to the app's
18.3.1 and installs a second, nested react-dom@19.2.4 beside it. npm reports
the resulting tree as invalid, and both renderers are included in the
production bundle.
Severity note: this does not crash the app. In a minimal repro it renders
correctly under both
vite devandvite preview, with no console errors,because the SDK's dist/index.js does not itself import react-dom — so the
mismatched copy is never executed. This is a dependency-hygiene and
bundle-size issue rather than a runtime failure, flagging that explicitly
since a crash report would not reproduce. The mismatched copy is, however,
genuinely broken if anything ever loads it directly:
React 19's react-dom reads
React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, whichReact 18.3.1 does not define.
Observed output —
npm ls react(tree marked invalid):npm ls react-dom(two copies):Both renderers reach the production bundle (confirmed by grepping the build
output for each version's internals symbol). Deduplicating them reduces the
bundle from 711,161 to 707,294 bytes (~3.9 kB raw, ~1.3 kB gzip of unused
renderer).
Root cause: react-dom is listed under "dependencies" rather than
"peerDependencies" in @asgardeo/react's package.json:
An exact 19.x pin for the renderer is incompatible with a >=16.8.0 peer range
for react, since react-dom must match the react it renders with.
Suggested fix: move react-dom and @types/react-dom to peerDependencies,
matching how react and @types/react are already handled.
Workaround used: npm
overridespinning the SDK's react-dom to the app'sown version, plus
resolve.dedupe: ["react", "react-dom"]in vite.config.js.Note: adding the override alone had no effect until the lockfile was
regenerated — the existing package-lock.json kept pinning 19.2.4 even after
npm reported the override as applied.