Before submitting a new issue
Bug Summary
On Android (New Architecture / Fabric), pressing the hardware back button while a presented sheet's native view is being torn down throws Error: Could not get native view tag. It's caught by RN's BackHandler emit and surfaces as a non-fatal in Crashlytics, but the back press silently no-ops and it pollutes crash reporting.
Introduced by #580, which routes hardware back through BackHandler.addEventListener('hardwareBackPress', this.handleBackPress).
The subscription is added in onDidPresent and only removed in onDidDismiss / componentWillUnmount. There is a window where the sheet's native view is detached (e.g. the host screen is popped/unmounted by navigation) before onDidDismiss runs to remove the subscription. In that window:
isPresented and isSheetVisible are both still true, so handleBackPress does not early-return, and
findNodeHandle(this.nativeRef.current) returns null
so the get handle() getter throws:
private get handle(): number {
const nodeHandle = findNodeHandle(this.nativeRef.current);
if (nodeHandle == null || nodeHandle === -1) {
throw new Error('Could not get native view tag'); // <-- thrown from BackHandler callback
}
return nodeHandle;
}
private handleBackPress(): boolean {
if (!this.isPresented || !this.isSheetVisible) return false;
TrueSheetModule?.handleBackPress(this.handle); // <-- reads throwing getter
return this.props.onBackPress?.() ?? true;
}
Affected Platforms
Library Version
3.10.0
Environment Info
React Native: 0.83.1, New Architecture (Fabric) enabled
Platform: Android only
Repro frequency increases on low-end devices (seen on a Redmi 9A / M2006C3MII, Helio G25)
Steps to Reproduce
It's a timing race, so it's flaky by hand (easier on a slow device / CPU-throttled emulator):
- Present a sheet hosted in a navigation screen.
- From inside the sheet, trigger navigation that unmounts the host screen without dismissing the sheet first.
- Spam the hardware back button during the transition.
Repro
https://github.com/sagnik2001/rn-true-sheet-backpress-repro
Additional Context
Resolve the node handle directly in handleBackPress and bail out cleanly if it's unavailable, instead of relying on the throwing getter:
private handleBackPress(): boolean {
if (!this.isPresented || !this.isSheetVisible) return false;
- TrueSheetModule?.handleBackPress(this.handle);
- // The native view can be detached (e.g. host screen unmounted by navigation)
- // before onDidDismiss removes this subscription. In that window the tag is
- // gone — treat back press as a no-op instead of throwing.
- const nodeHandle = findNodeHandle(this.nativeRef.current);
- if (nodeHandle == null || nodeHandle === -1) return false;
- TrueSheetModule?.handleBackPress(nodeHandle);
return this.props.onBackPress?.() ?? true;
}
Before submitting a new issue
Bug Summary
On Android (New Architecture / Fabric), pressing the hardware back button while a presented sheet's native view is being torn down throws Error: Could not get native view tag. It's caught by RN's BackHandler emit and surfaces as a non-fatal in Crashlytics, but the back press silently no-ops and it pollutes crash reporting.
Introduced by #580, which routes hardware back through BackHandler.addEventListener('hardwareBackPress', this.handleBackPress).
The subscription is added in onDidPresent and only removed in onDidDismiss / componentWillUnmount. There is a window where the sheet's native view is detached (e.g. the host screen is popped/unmounted by navigation) before onDidDismiss runs to remove the subscription. In that window:
isPresented and isSheetVisible are both still true, so handleBackPress does not early-return, and
findNodeHandle(this.nativeRef.current) returns null
so the get handle() getter throws:
private get handle(): number {
const nodeHandle = findNodeHandle(this.nativeRef.current);
if (nodeHandle == null || nodeHandle === -1) {
throw new Error('Could not get native view tag'); // <-- thrown from BackHandler callback
}
return nodeHandle;
}
private handleBackPress(): boolean {
if (!this.isPresented || !this.isSheetVisible) return false;
TrueSheetModule?.handleBackPress(this.handle); // <-- reads throwing getter
return this.props.onBackPress?.() ?? true;
}
Affected Platforms
Library Version
3.10.0
Environment Info
Steps to Reproduce
It's a timing race, so it's flaky by hand (easier on a slow device / CPU-throttled emulator):
Repro
https://github.com/sagnik2001/rn-true-sheet-backpress-repro
Additional Context
Resolve the node handle directly in handleBackPress and bail out cleanly if it's unavailable, instead of relying on the throwing getter:
private handleBackPress(): boolean {
if (!this.isPresented || !this.isSheetVisible) return false;
return this.props.onBackPress?.() ?? true;
}