-
Notifications
You must be signed in to change notification settings - Fork 25.1k
Description
Description
Summary
This appears to be a Fabric-specific bug that causes apps to crash when using third-party libraries that access refs to views containing Animated.View wrappers.
Key points:
- ✅ Works perfectly in Old Architecture (Bridge)
- ❌ Crashes immediately in New Architecture (Fabric)
- 💥 Same code, different behavior
The issue: In Fabric, refs to views wrapping Animated.View are null during initial render, causing NullPointerException when third-party libraries try to access them.
Question: Is this expected Fabric behavior, or a bug that should be fixed?
Environment
- React Native: 0.76.0+
- New Architecture: Enabled (
newArchEnabled=true) - Platform: Android (issue confirmed on Fabric)
The Problem
Behavior Comparison
| Aspect | Old Architecture (Bridge) | New Architecture (Fabric) |
|---|---|---|
| View mounting | ✅ Synchronous. | |
| Ref availability | ✅ Immediate | ❌ Delayed (can be null) |
| Same code behavior | ✅ Works | ❌ Crashes |
This is a Fabric-specific regression - code that works in Bridge crashes in Fabric.
Minimal Reproduction
I've created a minimal reproduction repository:
https://github.com/YOEL311/reproduceRNNewArchBug
The Issue
import { A11yOrder, useFocusOrder } from 'react-native-a11y';
import Animated from 'react-native-reanimated';
export default function App() {
const { a11yOrder, refs } = useFocusOrder(2);
return (
<A11yOrder a11yOrder={a11yOrder}>
<View ref={refs[0]}>
<Text>Component 1</Text>
</View>
{/* This crashes because refs[1] is null when A11yOrder tries to access it */}
<View ref={refs[1]}>
<Animated.View>
<Text>Animated Component</Text>
</Animated.View>
</View>
</A11yOrder>
);
}The Root Cause
Current code in react-native-a11y (A11yReader.java:88-95):
@RequiresApi(api = Build.VERSION_CODES.N)
public void setA11yOrder(@NonNull ReadableArray reactTags) {
final int length = reactTags.size();
if (length < 2) return;
final Activity activity = context.getCurrentActivity();
if (activity == null) {
return;
}
activity.runOnUiThread(() -> {
try {
RCA11yUIManagerHelper uiHelper = new RCA11yUIManagerHelper(context);
final ArrayList<View> views = new ArrayList<>();
for (int i = 0; i < length; i++) {
try {
views.add(uiHelper.resolveView(reactTags.getInt(i)));
} catch (IllegalViewOperationException error) {
Log.e("ERROR", error.getMessage());
}
}
for (int i = 0; i < views.size() - 1; i++) {
final View currentView = views.get(i);
final View nextView = views.get(i + 1);
currentView.setNextFocusForwardId(nextView.getId());
currentView.setAccessibilityTraversalBefore(nextView.getId());
}
} catch (IllegalViewOperationException error) {
Log.e("KEYBOARD_FOCUS_ERROR", error.getMessage());
}
});Why it crashes (Fabric-specific issue):
- In Old Architecture (Bridge): ✅ Works perfectly - Views mounted synchronously,
views.get(i + 1)always returns a valid View - In New Architecture (Fabric): ❌ Crashes - Views wrapped in
Animated.Viewmounted asynchronously,views.get(i + 1)returnsnull
This only happens in Fabric - the exact same code works without issues in the old architecture.
Workaround (But is it correct?)
The library can add a null check:
for (int i = 0; i < views.size() - 1; i++) {
final View currentView = views.get(i);
final View nextView = views.get(i + 1);
// ✅ This prevents the crash
if (currentView != null && nextView != null) {
currentView.setNextFocusForwardId(nextView.getId());
currentView.setAccessibilityTraversalBefore(nextView.getId());
}
}This works, but raises questions:
This Appears to Be a Bug - But Is It Expected?
The Fabric-Specific Issue
Scenario:
const { a11yOrder, refs } = useFocusOrder(2);
<A11yOrder a11yOrder={a11yOrder}>
<View ref={refs[0]}>...</View>
<View ref={refs[1]}>
<Animated.View>...</Animated.View>
</View>
</A11yOrder>;In Old Architecture: Both refs[0] and refs[1] are available ✅
In Fabric: refs[1] is null when accessed ❌
This looks like a bug because:
- Same code works in Bridge, crashes in Fabric
- No API changes were made
- No migration documentation mentions this
- Breaks backward compatibility
But we need clarification:
- Is this intentional Fabric behavior?
- Should all libraries add null checks for Fabric compatibility?
- Or will this be fixed in Fabric?
Question 2: What's the recommended pattern?
If null checks are the recommended approach:
if (currentView != null && nextView != null) {
// Safe to access
}But this silently fails:
- Accessibility ordering is skipped
- No error is reported
- Features break without developers knowing
Should libraries instead:
- Wait for mounting? (How? There's no callback)
- Retry with delays? (Unreliable and hacky)
- Log warnings? (What should the warning say?)
Question 3: Breaking change documentation?
If this is expected Fabric behavior, it's a breaking change from the old architecture.
Steps to reproduce
git clone https://github.com/YOEL311/reproduceRNNewArchBug
cd reproduceRNNewArchBug
yarn
yarn android
React Native Version
0.81.2
Affected Platforms
Runtime - Android
Areas
Fabric - The New Renderer
Output of npx @react-native-community/cli info
`
System:
OS: macOS 26.1
CPU: (12) arm64 Apple M3 Pro
Memory: 148.91 MB / 18.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.17.1
path: /Users/###/.nvm/versions/node/v22.17.1/bin/node
Yarn:
version: 1.22.22
path: /Users/###/.nvm/versions/node/v22.17.1/bin/yarn
npm:
version: 10.9.2
path: /Users/###/.nvm/versions/node/v22.17.1/bin/npm
Watchman:
version: 2025.05.26.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.2
- iOS 26.2
- macOS 26.2
- tvOS 26.2
- visionOS 26.2
- watchOS 26.2
Android SDK: Not Found
IDEs:
Android Studio: 2025.1 AI-251.25410.109.2511.13665796
Xcode:
version: 26.2/17C52
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.15
path: /Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 19.1.1
wanted: 19.1.1
react:
installed: 19.1.0
wanted: 19.1.0
react-native:
installed: 0.80.2
wanted: 0.80.2
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: Not found
newArchEnabled: false
`
Stacktrace or Logs
E FATAL EXCEPTION: main (Ask Gemini)
Process: com.test80, PID: 17622
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getId()' on a null object reference
at com.reactnativea11y.services.A11yReader.lambda$setA11yOrder$0(A11yReader.java:94)
at com.reactnativea11y.services.A11yReader.$r8$lambda$7Pp-de0q43EZIQ89q5T3KV4D0lE(Unknown Source:0)
at com.reactnativea11y.services.A11yReader$$ExternalSyntheticLambda1.run(D8$$SyntheticClass:0)
at android.os.Handler.handleCallback(Handler.java:995)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loopOnce(Looper.java:273)
at android.os.Looper.loop(Looper.java:363)
at android.app.ActivityThread.main(ActivityThread.java:10060)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:632)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
`
MANDATORY Reproducer
https://github.com/YOEL311/reproduceRNNewArchBug
Screenshots and Videos
App crashes immediately on launch with NullPointerException when using react-native-a11y with Fabric enabled.