Repository navigation
Description
Description
react-native/packages/react-native/src/private/webapis/structuredClone/structuredClone.js
Line 298 in 649c105
| const NON_SERIALIZABLE_OBJECT_KEY = Symbol('nonSerializableObject'); |
react-native/packages/react-native/src/private/webapis/structuredClone/structuredClone.js
Lines 394 to 407 in 649c105
| function isNonSerializableObject<T extends interface {}>(obj: T): boolean { | |
| // $FlowExpectedError[invalid-in-lhs] | |
| return NON_SERIALIZABLE_OBJECT_KEY in obj; | |
| } | |
| function markClassAsNonSerializable<T>(cls: Class<T>): void { | |
| // $FlowExpectedError[incompatible-use] | |
| cls.prototype[NON_SERIALIZABLE_OBJECT_KEY] = true; | |
| } | |
| // Non-serializable built-ins. | |
| markClassAsNonSerializable(WeakMap); | |
| markClassAsNonSerializable(WeakSet); | |
| markClassAsNonSerializable(Promise); |
crashes apps whose built-in prototypes are frozen (Hardened JS / SES)
i.e. via LavaMoat React Native lockdown
e.g. react-native-template-new-architecture
unless patched with the/a fix when upgrading to v0.89
when apps like metamask/metamask-mobile eventually adopt v0.89 stable
they will crash on first render as soon as structuredClone loads
TypeError: cannot add a new property
at markClassAsNonSerializable (structuredClone.js:401:45)
at anonymous (structuredClone.js:405:27)
...
at metroRequire (require.js:98:24)
at metroImportDefault (require.js:123:31)
at measure (Performance.js:343:30)
at renderRootSync (ReactFabric-dev.js:15001:26)
at performWorkOnRootViaSchedulerTask (ReactFabric.js:3928:24)
then remaining calls fail since structuredClone is undefined
TypeError: undefined is not a function
at measure (Performance.js:343:30)
...
Error: Should not already be working.
at performWorkOnRoot (ReactFabric-dev.js:14078:20)
... the measure frame: performance.measure() called with a detail
343: (structuredClone(detail)) is behind the detail !== undefined guard
so the crashing call must have passed a detail
performance.mark() with a detail fails similarly
structuredClone.js currently marks built-in classes non-serializable by adding the symbol prop to the built-in prototypes at the module top level
since the built-in prototypes are frozen (non-extensible) and RN source is strict-mode
the first cls.prototype[SYMBOL] = true throws during eval on WeakMap
structuredClone installs lazily
setUpDOM.js: polyfillGlobal('structuredClone', () => require('../webapis/structuredClone/structuredClone').default)
the first use runs that require and throws, the factory's require(...).default never resolves, so the structuredClone global is left undefined
the first throw is contained rather than fatal (the app still reaches later structuredClone uses), so every following use fails with undefined is not a function
so the first performance.measure(name, { detail }) during the first render (Fabric dev instrumentation) lazily loads structuredClone.js then throws at its top level
its not a new mutation, 0.88.1 includes the module (same code), but 0.89 pulled the module into the startup path
245bbfaf0a exposes structuredClone/DOMException as globals in packages/react-native/src/private/setup/setUpDOM.js (not in 0.88.1)
14de25bb2d extends structuredClone with ArrayBuffer/DataView/typed array/BigInt/Error support, and Performance.js (imported by startup timing) calls structuredClone in mark()/measure() whenever detail is defined
as an aside spotted couple spec-compliant gaps RE WeakRef and FinalizationRegistry which i'll follow up seperately
Steps to reproduce
1a. clone react-native-template-new-architecture
1b. checkout to branch react-native-0.88.1-to-0.89.0-rc.0-repro
2. run yarn android or yarn ios
React Native Version
0.89.0-rc.0
Affected Platforms
Runtime - iOS, Runtime - Android
Output of npx @react-native-community/cli info
npx @react-native-community/cli info
info Fetching system and libraries information...
System:
OS: macOS 27.3
CPU: (12) arm64 Apple M2 Pro
Memory: 612.80 MB / 16.00 GB
Shell:
version: 5.9.2
path: /opt/homebrew/bin/zsh
Binaries:
Node:
version: 22.23.1
path: /Users/leo/.local/state/fnm_multishells/29305_1794588089192/bin/node
Yarn:
version: 4.18.1
path: /Users/leo/.local/state/fnm_multishells/29305_1794588089192/bin/yarn
npm:
version: 10.9.8
path: /Users/leo/.local/state/fnm_multishells/29305_1794588089192/bin/npm
Watchman: Not Found
Managers:
CocoaPods:
version: 1.17.0
path: /var/folders/w0/pbc5gqt14yjg4b1y7s6x6wpw0000gn/T/frum_29306_1794588089207/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 27.3
- iOS 27.3
- macOS 27.3
- tvOS 27.3
- visionOS 27.3
- watchOS 27.3
Android SDK: Not Found
IDEs:
Android Studio: Not Found
Xcode:
version: 27.3/27C5020n
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.21.0.3
path: /Users/leo/.jenv/shims/javac
Ruby:
version: 3.4.10
path: /var/folders/w0/pbc5gqt14yjg4b1y7s6x6wpw0000gn/T/frum_29306_1794588089207/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 21.0.0-alpha.1
wanted: 21.0.0-alpha.1
react:
installed: 19.3.0
wanted: 19.3.0
react-native:
installed: 0.89.0-rc.0
wanted: 0.89.0-rc.0
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
Stacktrace or Logs
Running "MyApp" with {"rootTag":11,"initialProps":{},"fabric":true}
console.js:667 TypeError: cannot add a new property
at markClassAsNonSerializable (structuredClone.js:401:45)
at anonymous (structuredClone.js:405:27)
at loadModuleImplementation (require.js:285:12)
at guardedLoadModule (require.js:183:45)
at metroRequire (require.js:98:24)
at metroImportDefault (require.js:123:31)
at measure (Performance.js:343:30)
at run (native)
at prepareFreshStack (ReactFabric-dev.js:14720:28)
at renderRootSync (ReactFabric-dev.js:15001:26)
at performWorkOnRoot (ReactFabric-dev.js:14158:25)
at performWorkOnRootViaSchedulerTask (ReactFabric-dev.js:3928:24)
anonymous @ console.js:667
overrideMethod @ backend.js:17416
reactConsoleErrorHandler @ ExceptionsManager.js:184
anonymous @ setUpDeveloperTools.js:42
reportException @ ExceptionsManager.js:108
handleException @ ExceptionsManager.js:173
handleError @ setUpErrorHandling.js:26
reportFatalError @ error-guard.js:53
guardedLoadModule @ require.js:185
metroRequire @ require.js:98
metroImportDefault @ require.js:123
measure @ Performance.js:343
prepareFreshStack @ ReactFabric-dev.js:14720
renderRootSync @ ReactFabric-dev.js:15001
performWorkOnRoot @ ReactFabric-dev.js:14158
performWorkOnRootViaSchedulerTask @ ReactFabric-dev.js:3928
console.js:667 TypeError: undefined is not a function
at measure (Performance.js:343:30)
at run (native)
at prepareFreshStack (ReactFabric-dev.js:14720:28)
at renderRootSync (ReactFabric-dev.js:15001:26)
at performWorkOnRoot (ReactFabric-dev.js:14158:25)
at performWorkOnRootViaSchedulerTask (ReactFabric-dev.js:3928:24)
anonymous @ console.js:667
overrideMethod @ backend.js:17416
reactConsoleErrorHandler @ ExceptionsManager.js:184
anonymous @ setUpDeveloperTools.js:42
reportException @ ExceptionsManager.js:108
handleException @ ExceptionsManager.js:173
handleError @ setUpErrorHandling.js:26
reportFatalError @ error-guard.js:53
console.js:667 Error: Should not already be working.
at performWorkOnRoot (ReactFabric-dev.js:14078:20)
at performWorkOnRootViaSchedulerTask (ReactFabric-dev.js:3928:24)
MANDATORY Reproducer
https://github.com/leotm/react-native-template-new-architecture
Screenshots and Videos
No response
Activity
Fix structuredClone WeakMap/WeakSet/Promise prototype mutations for H…
Upgrade react-native from v0.88.1 to v0.89.0-rc.0 (#2123)