Skip to content

Navigation Menu

Sign in
Sign up

Fix "Cannot read property 'canonical' of undefined" in Fabric getListener when event target is not a live fiber - #58418

Open
heecheolman wants to merge 1 commit into
react:main from
heecheolman:fix/getlistener-undefined-statenode
Open

Fix "Cannot read property 'canonical' of undefined" in Fabric getListener when event target is not a live fiber #58418
heecheolman wants to merge 1 commit into
react:main from
heecheolman:fix/getlistener-undefined-statenode

Conversation

@heecheolman

@heecheolman heecheolman commented Sep 9, 2026

Copy link
Copy Markdown

Summary:

Fixes a production crash in the Fabric legacy event system:

 TypeError: Cannot read property 'canonical' of undefined
 at getListener (ReactFabric-dev.js:997)

getListener guards the fiber's stateNode with a strict null check:

inst = inst.stateNode;
if (null === inst) return null;
inst = getFiberCurrentPropsFromNode(inst); // → instance.canonical.currentProps

Inside the reconciler this is sufficient — stateNode is initialized to null in the
FiberNode constructor, reset to null in detachFiberAfterEffects (including the
alternate), and only ever assigned instance objects in completeWork — so undefined
cannot be produced by React itself.

However, the responder event path receives its target from native dispatch across the
JSI boundary
. The instance handle is stored natively as a weak reference
(EventTarget/InstanceHandle, where a dead jsi::WeakObject::lock() yields
undefined rather than null), so when a touch is delivered for a view that unmounted
mid-gesture (screen transition on press, sheet dismissal, list cell recycling), the
target reaching the plugins is no longer guaranteed to be a live host fiber. Reading
.stateNode on such a target yields undefined, which passes the strict === null
check and crashes one line later in getFiberCurrentPropsFromNode with the error above.

This change loosens the check to null == inst, matching the guards already used at the
other entry points of the same pipeline (null != target in dispatchEvent,
null == targetInst in ReactNativeBridgeEventPlugin.extractEvents). With the guard,
the event for a dead target is dropped instead of throwing.

We are seeing this crash in production (React Native 0.84.0, Hermes, new architecture)
reported to Sentry as an unhandled error, correlated with touches during unmount.

Note: ReactFabric-{dev,prod,profiling}.js are generated bundles synced from
facebook/react — the source counterpart of this fix is
packages/react-native-renderer/src/ReactNativeGetListener.js (and its inlined copy in
ResponderEventPlugin). Happy to redirect this patch there if that is the preferred
route; filing here first since the crash manifests in React Native releases.

Changelog:

[GENERAL] [FIXED] - Fix "Cannot read property 'canonical' of undefined" crash in Fabric event dispatch when a touch is delivered to a view unmounted mid-gesture

Test Plan:

  • Verified via code inspection that undefined cannot originate from the reconciler
    itself (FiberNode constructor, detachFiberAfterEffects, and every stateNode
    assignment in completeWork only ever produce an object or null), so the loosened
    check only affects out-of-contract targets coming from native dispatch — for which
    every sibling guard in this pipeline already uses loose null checks.
  • The change is limited to the stateNode guard in the two inlined copies of
    getListener (responder plugin + plugin registry) in each of the three generated
    bundles; the subsequent props guard is untouched. yarn jest react-native passes.
  • Reproduction scenario: start a touch on a pressable row and unmount it before the
    event is processed (e.g. navigation triggered by the same interaction, or a recycled
    list removing the row). Before this change the dispatch throws the TypeError above;
    after it, the stale touch is ignored.

...defined
getListener guards the fiber's stateNode with a strict null check:
 inst = inst.stateNode;
 if (null === inst) return null;
Within the reconciler this is sufficient (stateNode is initialized to
null and reset to null on detach), but the responder event path receives
its target from native dispatch. When the instance handle delivered
across the JSI boundary is no longer a live host fiber (e.g. a touch
delivered after the view unmounted), reading .stateNode yields undefined,
which passes the strict check and crashes in getFiberCurrentPropsFromNode
with "Cannot read property 'canonical' of undefined".
Loosen the check to `null == inst`, matching the surrounding event-plugin
guards (`null != target`, `null == targetInst`), so the event is dropped
for a dead target instead of throwing.
Note: ReactFabric-* bundles are generated from facebook/react; the source
counterpart is packages/react-native-renderer/src/ReactNativeGetListener.js
(and its inlined copy in the responder plugin).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 9, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

AltStyle によって変換されたページ (->オリジナル) /