You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Due for payment 2026-04-14] [$250] Android - Accounting - Error message overlapped by OS navigation buttons #84841
Version Number: v9.3.35-0 Reproducible in staging?: Yes Reproducible in production?: Yes If this was caught during regression testing, add the test name, ID and link from BrowserStack:https://test-management.browserstack.com/projects/2219752/folder/13176908/test-cases/41237444 Email or phone of affected tester (no customers):testexpensify9+kdii@gmail.com Issue reported by: Applause Internal Team Bug source: Regression TC Execution Device used: Android 16, Samsung A15. App Component: Workspace Settings
Action Performed:
Preconditions:
The user has a workspace.
QBO UK is connected in accounting.
Open the app.
Go to Workspaces > {select the WS with QBO UK connected} > Accounting > Export > Export out-of-pocket expenses > Export as > Vendor bill
Expected Result:
When selecting Vendor Bill in Export as, the error message should be displayed clearly and fully visible to allow the user tap on X to close it.
Actual Result:
After selecting Vendor Bill in Export as, the error message is partially hidden/overlapped by the OS navigation buttons.
Please re-state the problem that we are trying to solve in this issue.
On Android, when selecting "Vendor Bill" in the QBO UK export settings (Workspaces > Accounting > Export > Export out-of-pocket expenses > Export as), the error message that appears is partially hidden behind the Android OS navigation buttons, making the dismiss (X) button inaccessible.
What is the root cause of that problem?
The SelectionScreen component disables bottom safe area padding on the SelectionList whenever errors are present, but the ErrorMessageRow that replaces it has no safe area padding of its own.
Specifically, in src/components/SelectionScreen.tsx:186:
When errors exist, this evaluates to false. This means the outer View in BaseSelectionList (at src/components/SelectionList/BaseSelectionList.tsx:532) does not apply bottom safe area padding:
The ErrorMessageRow is rendered as children at line 565 of BaseSelectionList, positioned after the FlashList but with no bottom safe area inset applied to it. Meanwhile, ScreenWrapper is in edge-to-edge mode (enableEdgeToEdgeBottomSafeAreaPadding at SelectionScreen.tsx:157), which explicitly delegates bottom safe area responsibility to child components. Since no component in the hierarchy adds the padding when errors are showing, the error message sits flush at the bottom of the screen and gets overlapped by Android's navigation bar.
What changes do you think we should make in order to solve the problem?
In src/components/SelectionScreen.tsx, change addBottomSafeAreaPadding to always be true on the SelectionList, removing the conditional that disables it when errors exist:
This ensures the outer container View in BaseSelectionList always applies its bottom safe area padding style, which will push the ErrorMessageRow (rendered as children) above the Android navigation bar. When there are no errors, ErrorMessageRow renders null, so the padding simply applies to the bottom of the list as it does today.
What alternative solutions did you explore? (Optional)
Adding safe area padding directly to ErrorMessageRow/MessagesRow — This would work but would require the error component to be safe-area-aware, coupling a generic UI component to platform-specific layout concerns.
Moving ErrorMessageRow into footerContent instead of children — This would leverage FixedFooter's built-in safe area handling, but would change the visual layout and require refactoring how errors are passed through SelectionScreen.
The simplest and most correct fix is option described above: always keep addBottomSafeAreaPadding enabled. The original intent of disabling it when errors show appears to have been an optimization to avoid extra padding, but the ErrorMessageRow itself doesn't compensate, creating the gap.
Next Steps for Contributor+ team: Reply with @MelvinBot implement this to create a draft PR, @MelvinBot <your feedback> to refine this analysis, or explain why you are rejecting Melvin's proposal.
changed the title [-]Android - Accounting - Error message overlapped by OS navigation buttons[/-][+][$250] Android - Accounting - Error message overlapped by OS navigation buttons[/+]on Mar 11, 2026
Please re-state the problem that we are trying to solve in this issue.
On Android, when you select "Vendor Bill" in the QBO UK export settings, an error message appears at the bottom of the screen but gets hidden behind the OS navigation buttons. The dismiss (X) button is inaccessible, so users can't clear the error without navigating away.
What is the root cause of that problem?
This is a regression introduced in commit 128537cfd5b (Apr 11, 2025, "refactor: make all ConnectionLayout and SelectionScreen edge-to-edge by default").
Before that commit, ScreenWrapper had includeSafeAreaPaddingBottom={!!errors && !isEmptyObject(errors)}, which added bottom safe area padding specifically when errors were showing. The refactor switched SelectionScreen to edge-to-edge mode (enableEdgeToEdgeBottomSafeAreaPadding at line 157), which delegates safe area responsibility to child components. The padding logic moved to SelectionList via addBottomSafeAreaPadding — but the condition got inverted.
In SelectionScreen.tsx at line 186, addBottomSafeAreaPadding={!errors || isEmptyObject(errors)} evaluates to false when errors exist. This means BaseSelectionList's container View (line 532) skips its paddingBottomStyle, and ErrorMessageRow — rendered as {children} at line 565 with no safe area handling of its own — ends up behind Android's navigation bar.
What changes do you think we should make in order to solve the problem?
In src/components/SelectionScreen.tsx line 186, remove the conditional and change addBottomSafeAreaPadding={!errors || isEmptyObject(errors)} to just addBottomSafeAreaPadding.
This way the container always applies safe area padding. When no errors exist, ErrorMessageRow renders null, so the padding applies to the list bottom — identical to current behavior. The fix is also safe when the keyboard is open (paddingBottomStyle returns false at line 118) and when a footer is present (!hasFooter check at line 532 prevents double padding).
What alternative solutions did you explore? (Optional)
I looked at adding useBottomSafeSafeAreaPaddingStyle directly inside ErrorMessageRow, similar to how FixedFooter handles it. This works but couples a generic UI component to platform-specific layout — and since ErrorMessageRow is used in many places, it risks double padding in contexts where the parent already provides it.
I also considered moving ErrorMessageRow into footerContent to leverage FixedFooter's built-in safe area handling, but that changes the visual layout and introduces hasFooter side effects on the container's own padding logic. The one-line prop fix is the minimal and safest path.
Hi Expensify team, I reviewed issue #84841 and I've already prepared the technical fix. We've encountered the same Android edge-to-edge overlap in production and resolved it cleanly.
Root cause: on Android 15+ (targeting SDK 35+), the app renders edge-to-edge and the "Export as > Vendor bill" screen's bottom error message isn't applying system bar insets, so it's covered by the navigation bar.
Fix: wrap the affected screen (or the error message container) with SafeAreaView from react-native-safe-area-context and apply the bottom edge inset:
<SafeAreaView edges={['bottom']} style={{flex: 1}}>
{existing content including the error message}
This adds bottom padding equal to the navigation bar height and prevents overlap across gesture/3-button modes
📣 @Ehtishamulhaq2k2! 📣
Hey, it seems we don’t have your contributor details yet! You'll only have to do this once, and this is how we'll hire you on Upwork.
Please follow these steps:
Get the email address used to login to your Expensify account. If you don't already have an Expensify account, create one here. If you have multiple accounts (e.g. one for testing), please use your main account email.
Get the link to your Upwork profile. It's necessary because we only pay via Upwork. You can access it by logging in, and then clicking on your name. It'll look like this. If you don't already have an account, sign up for one here.
Copy the format below and paste it in a comment on this issue. Replace the placeholder text with your actual details.
Format:
Contributor details
Your Expensify account email: <REPLACE EMAIL HERE>
Upwork Profile Link: <REPLACE LINK HERE>
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.3.52-9 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
@FitseTLT / @Krishna2323 The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]
Issue is ready for payment but no BZ is assigned. @mallenexpensify you are the lucky winner! Please verify the payment summary looks correct and complete the checklist. Thanks!
Activity
melvin-bot commentedon Mar 11, 2026
Triggered auto assignment to @laurenreidexpensify (
Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.MelvinBot commentedon Mar 11, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android, when selecting "Vendor Bill" in the QBO UK export settings (Workspaces > Accounting > Export > Export out-of-pocket expenses > Export as), the error message that appears is partially hidden behind the Android OS navigation buttons, making the dismiss (X) button inaccessible.
What is the root cause of that problem?
The
SelectionScreencomponent disables bottom safe area padding on theSelectionListwhenever errors are present, but theErrorMessageRowthat replaces it has no safe area padding of its own.Specifically, in
src/components/SelectionScreen.tsx:186:When errors exist, this evaluates to
false. This means the outerViewinBaseSelectionList(atsrc/components/SelectionList/BaseSelectionList.tsx:532) does not apply bottom safe area padding:The
ErrorMessageRowis rendered aschildrenat line 565 ofBaseSelectionList, positioned after theFlashListbut with no bottom safe area inset applied to it. Meanwhile,ScreenWrapperis in edge-to-edge mode (enableEdgeToEdgeBottomSafeAreaPaddingatSelectionScreen.tsx:157), which explicitly delegates bottom safe area responsibility to child components. Since no component in the hierarchy adds the padding when errors are showing, the error message sits flush at the bottom of the screen and gets overlapped by Android's navigation bar.What changes do you think we should make in order to solve the problem?
In
src/components/SelectionScreen.tsx, changeaddBottomSafeAreaPaddingto always betrueon theSelectionList, removing the conditional that disables it when errors exist:(i.e., remove
={!errors || isEmptyObject(errors)})This ensures the outer container
ViewinBaseSelectionListalways applies its bottom safe area padding style, which will push theErrorMessageRow(rendered aschildren) above the Android navigation bar. When there are no errors,ErrorMessageRowrendersnull, so the padding simply applies to the bottom of the list as it does today.What alternative solutions did you explore? (Optional)
ErrorMessageRow/MessagesRow— This would work but would require the error component to be safe-area-aware, coupling a generic UI component to platform-specific layout concerns.ErrorMessageRowintofooterContentinstead ofchildren— This would leverageFixedFooter's built-in safe area handling, but would change the visual layout and require refactoring how errors are passed throughSelectionScreen.The simplest and most correct fix is option described above: always keep
addBottomSafeAreaPaddingenabled. The original intent of disabling it when errors show appears to have been an optimization to avoid extra padding, but theErrorMessageRowitself doesn't compensate, creating the gap.Next Steps for Contributor+ team: Reply with
@MelvinBot implement thisto create a draft PR,@MelvinBot <your feedback>to refine this analysis, or explain why you are rejecting Melvin's proposal.melvin-bot commentedon Mar 11, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @Krishna2323 (
External)[-]Android - Accounting - Error message overlapped by OS navigation buttons[/-][+][$250] Android - Accounting - Error message overlapped by OS navigation buttons[/+]melvin-bot commentedon Mar 11, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022031619974317786098
shivang-goliyan commentedon Mar 11, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On Android, when you select "Vendor Bill" in the QBO UK export settings, an error message appears at the bottom of the screen but gets hidden behind the OS navigation buttons. The dismiss (X) button is inaccessible, so users can't clear the error without navigating away.
What is the root cause of that problem?
This is a regression introduced in commit
128537cfd5b(Apr 11, 2025, "refactor: make all ConnectionLayout and SelectionScreen edge-to-edge by default").Before that commit,
ScreenWrapperhadincludeSafeAreaPaddingBottom={!!errors && !isEmptyObject(errors)}, which added bottom safe area padding specifically when errors were showing. The refactor switched SelectionScreen to edge-to-edge mode (enableEdgeToEdgeBottomSafeAreaPaddingat line 157), which delegates safe area responsibility to child components. The padding logic moved toSelectionListviaaddBottomSafeAreaPadding— but the condition got inverted.In
SelectionScreen.tsxat line 186,addBottomSafeAreaPadding={!errors || isEmptyObject(errors)}evaluates tofalsewhen errors exist. This meansBaseSelectionList's containerView(line 532) skips itspaddingBottomStyle, andErrorMessageRow— rendered as{children}at line 565 with no safe area handling of its own — ends up behind Android's navigation bar.What changes do you think we should make in order to solve the problem?
In
src/components/SelectionScreen.tsxline 186, remove the conditional and changeaddBottomSafeAreaPadding={!errors || isEmptyObject(errors)}to justaddBottomSafeAreaPadding.This way the container always applies safe area padding. When no errors exist,
ErrorMessageRowrendersnull, so the padding applies to the list bottom — identical to current behavior. The fix is also safe when the keyboard is open (paddingBottomStylereturnsfalseat line 118) and when a footer is present (!hasFootercheck at line 532 prevents double padding).What alternative solutions did you explore? (Optional)
I looked at adding
useBottomSafeSafeAreaPaddingStyledirectly insideErrorMessageRow, similar to howFixedFooterhandles it. This works but couples a generic UI component to platform-specific layout — and sinceErrorMessageRowis used in many places, it risks double padding in contexts where the parent already provides it.I also considered moving
ErrorMessageRowintofooterContentto leverageFixedFooter's built-in safe area handling, but that changes the visual layout and introduceshasFooterside effects on the container's own padding logic. The one-line prop fix is the minimal and safest path.Ehtishamulhaq2k2 commentedon Mar 11, 2026
Hi Expensify team, I reviewed issue #84841 and I've already prepared the technical fix. We've encountered the same Android edge-to-edge overlap in production and resolved it cleanly.
Root cause: on Android 15+ (targeting SDK 35+), the app renders edge-to-edge and the "Export as > Vendor bill" screen's bottom error message isn't applying system bar insets, so it's covered by the navigation bar.
Fix: wrap the affected screen (or the error message container) with SafeAreaView from react-native-safe-area-context and apply the bottom edge inset:
<SafeAreaView edges={['bottom']} style={{flex: 1}}>
{existing content including the error message}
This adds bottom padding equal to the navigation bar height and prevents overlap across gesture/3-button modes
melvin-bot commentedon Mar 11, 2026
📣 @Ehtishamulhaq2k2! 📣
Hey, it seems we don’t have your contributor details yet! You'll only have to do this once, and this is how we'll hire you on Upwork.
Please follow these steps:
Format:
32 remaining items
melvin-bot commentedon Apr 7, 2026
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.3.52-9 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-04-14. 🎊
For reference, here are some details about the assignees on this issue:
melvin-bot commentedon Apr 7, 2026
@FitseTLT / @Krishna2323 The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]
melvin-bot commentedon Apr 7, 2026
Triggered auto assignment to @mallenexpensify (
Awaiting Payment)melvin-bot commentedon Apr 14, 2026
Issue is ready for payment but no BZ is assigned. @mallenexpensify you are the lucky winner! Please verify the payment summary looks correct and complete the checklist. Thanks!
laurenreidexpensify commentedon Apr 15, 2026
Payment Summary
$250 @FitseTLT paid in Upwork
$250 @Krishna2323 can request in New Expensify
Krishna2323 commentedon Apr 17, 2026
Requested in ND.
laurenreidexpensify commentedon Apr 20, 2026
@Krishna2323 $250 approved in New Expensify