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-03-02] [$250] GBR briefly reappears on LHN when approver leave workspace #75329
Version Number: v9.2.59-1 Reproducible in staging?: Yes Reproducible in production?: Yes If this was caught during regression testing, add the test name, ID and link from BrowserStack: n/a Email or phone of affected tester (no customers):gocemate+b2155426@gmail.com Issue reported by: Applause Internal Team Device used: Lenovo 80ES / Windows 10 Pro App Component: Left Hand Navigation (LHN)
Action Performed:
Precondition: Owner create workspace and invite employee and approver. Submission frequency in Workflows needs to be disabled
Employee submits 2 expenses in workspace chat
Approver approve the expenses
Approver navigates to workspaces> leave the workspace
Approver navigates back to inbox
Expected Result:
Green dot should not appear on workspace chat
Actual Result:
Green dot appears briefly when approver leaves the workspace
changed the title [-]GBR briefly reappears on LHN when approver leave workspace[/-][+][$250] GBR briefly reappears on LHN when approver leave workspace[/+]on Nov 19, 2025
It happens because when you leave the workspace, you don't actually touch the iou reports, and so the managerId is equal still temporarily to the approved id.
What changes do you think we should make in order to solve the problem?
to basically leave early if the policy is not there. Note it is a bit more tricky for canIOUBePaid as it can also be used outside of workspace context.
function canApproveIOU(iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report>, policy: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Policy>, iouTransactions?: OnyxTypes.Transaction[]) {
// Only expense reports can be approved
if (!isExpenseReport(iouReport) || !(policy && isPaidGroupPolicy(policy))) {
return false;
}
const currentUserLogin = getLoginByAccountID(userAccountID);
if (!isPolicyMember(policy, currentUserLogin)) {
return false;
}
const isOnSubmitAndClosePolicy = isSubmitAndClose(policy);
if (isOnSubmitAndClosePolicy) {
return false;
}
What alternative solutions did you explore? (Optional)
N/A
Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.
Summary: GBR (green brick road indicator) briefly reappears on the LHN when an approver leaves a workspace. This happens because the isPayer() function falls through to a permissive return path when the policy is removed from Onyx.
Status: ✅ Resolved — Fixed by App PR #78421 (merged 2026-02-20, deployed in v9.3.24-3) and Auth PR #19678 (BE fix).
Root Cause: When the approver leaves a workspace, the LeavePolicy API call removes the policy from Onyx. During the brief window where the policy is null, isPayer() in ReportUtils.ts incorrectly returns true because:
isPaidGroupPolicy(iouReport) calls getPolicyType(), which returns '' for a null policy → isPaidGroupPolicy returns false
This causes isPayer() to skip the paid-group-policy logic block entirely
Execution falls through to the permissive fallback: return isAdmin || (isMoneyRequestReport(iouReport) && isManager)
Since the user was the approver (manager), isManager is true, so isPayer() incorrectly returns true
This cascades through canIOUBePaid() → getIOUReportActionToApproveOrPay() → requiresAttentionFromCurrentUser() → reportAttributes derived value → green brick road indicator in LHN.
Fix Applied: Early return false in isPayer() when the policy is null and the report belongs to a workspace (has a valid policyID). This prevents the entire downstream cascade.
Detailed Investigation
Evidence Chain
The complete data flow from trigger to symptom:
Trigger: User leaves workspace → LeavePolicy API removes policy from Onyx
isPayer() (ReportUtils.ts:2732-2786) — resolves policy as null, isPaidGroupPolicy() returns false due to getPolicyType() returning '' (ReportUtils.ts:1396-1398), falls through to permissive return isAdmin || (isMoneyRequestReport && isManager) → incorrectly returns true
getIOUReportActionToApproveOrPay() (IOU/index.ts:10524-10545) — finds a REPORT_PREVIEW action where shouldShowSettlementButton is true → returns the action
requiresAttentionFromCurrentUser() (ReportUtils.ts:4271-4288) — sees non-null iouReportActionToApproveOrPay → returns HAS_CHILD_REPORT_AWAITING_ACTION
Added an early membership check at the top of isPayer():
// If the report belongs to a workspace, verify the user is still a memberif(!isIOUReport(iouReport)&&iouReport?.policyID&&iouReport.policyID!==CONST.POLICY.ID_FAKE){if(!policy){returnfalse;}if(isPaidGroupPolicy(iouReport)&&!isEmptyObject(policy?.employeeList)&&!isPolicyMemberWithoutPendingDelete(currentUserEmailParam,policy)){returnfalse;}}
This ensures that when the policy is removed from Onyx (user left workspace), isPayer() immediately returns false, preventing the entire downstream chain.
Files Changed
src/libs/actions/Policy/Policy.ts — Added early return logic
src/pages/workspace/WorkspaceOverviewPage.tsx — Minor related update
src/pages/workspace/WorkspacesListPage.tsx — Minor related update
tests/actions/PolicyTest.ts — Added test coverage for the fix
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: Not Required. The existing checklist is good enough to capture such issues.
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
Regression Test Proposal Template
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Activity
melvin-bot commentedon Nov 17, 2025
Triggered auto assignment to @garrettmknight (
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.[-]GBR briefly reappears on LHN when approver leave workspace[/-][+][$250] GBR briefly reappears on LHN when approver leave workspace[/+]melvin-bot commentedon Nov 19, 2025
Job added to Upwork: https://www.upwork.com/jobs/~021991222255923911951
melvin-bot commentedon Nov 19, 2025
Triggered auto assignment to Contributor-plus team member for initial proposal review - @rojiphil (
External)imadirtydog commentedon Nov 22, 2025
Proposal
Please re-state the problem that we are trying to solve in this issue.
GBR briefly reappears on LHN when approver leave workspace.
What is the root cause of that problem?
The brick road status is gotten from reportAttributes createOnyxDerivedValueConfig
requiresAttention tag is briefly true when we first click back on the inbox, because shouldShowSettlementButton resolves to true
App/src/libs/actions/IOU.ts
Line 10303 in 1d0ce34
It happens because when you leave the workspace, you don't actually touch the iou reports, and so the managerId is equal still temporarily to the approved id.
What changes do you think we should make in order to solve the problem?
We can modify the canApproveIOU
App/src/libs/actions/IOU.ts
Line 10153 in 1d0ce34
App/src/libs/actions/IOU.ts
Line 10153 in 1d0ce34
to basically leave early if the policy is not there. Note it is a bit more tricky for canIOUBePaid as it can also be used outside of workspace context.
What alternative solutions did you explore? (Optional)
N/A
Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.
59 remaining items
garrettmknight commentedon Feb 26, 2026
@rojiphil checklist when you get a chance.
garrettmknight commentedon Feb 26, 2026
@mallenexpensify just handing off for payment while I'm out. Thanks!
MelvinBot commentedon Feb 26, 2026
🔍 Issue Analysis
Summary: GBR (green brick road indicator) briefly reappears on the LHN when an approver leaves a workspace. This happens because the
isPayer()function falls through to a permissive return path when the policy is removed from Onyx.Status: ✅ Resolved — Fixed by App PR #78421 (merged 2026-02-20, deployed in v9.3.24-3) and Auth PR #19678 (BE fix).
Root Cause: When the approver leaves a workspace, the
LeavePolicyAPI call removes the policy from Onyx. During the brief window where the policy is null,isPayer()inReportUtils.tsincorrectly returnstruebecause:isPaidGroupPolicy(iouReport)callsgetPolicyType(), which returns''for a null policy →isPaidGroupPolicyreturnsfalseisPayer()to skip the paid-group-policy logic block entirelyreturn isAdmin || (isMoneyRequestReport(iouReport) && isManager)isManageristrue, soisPayer()incorrectly returnstrueThis cascades through
canIOUBePaid()→getIOUReportActionToApproveOrPay()→requiresAttentionFromCurrentUser()→reportAttributesderived value → green brick road indicator in LHN.Fix Applied: Early return
falseinisPayer()when the policy is null and the report belongs to a workspace (has a validpolicyID). This prevents the entire downstream cascade.Detailed Investigation
Evidence Chain
The complete data flow from trigger to symptom:
LeavePolicyAPI removes policy from OnyxisPayer()(ReportUtils.ts:2732-2786) — resolves policy asnull,isPaidGroupPolicy()returnsfalsedue togetPolicyType()returning''(ReportUtils.ts:1396-1398), falls through to permissivereturn isAdmin || (isMoneyRequestReport && isManager)→ incorrectly returnstruecanIOUBePaid()(IOU/index.ts:10423-10488) — callsisPayer, getstrue→ returnstruegetIOUReportActionToApproveOrPay()(IOU/index.ts:10524-10545) — finds aREPORT_PREVIEWaction whereshouldShowSettlementButtonistrue→ returns the actionrequiresAttentionFromCurrentUser()(ReportUtils.ts:4271-4288) — sees non-nulliouReportActionToApproveOrPay→ returnsHAS_CHILD_REPORT_AWAITING_ACTIONreportAttributes(reportAttributes.ts:202-210) — setsbrickRoadStatus = INFO(green)SidebarUtils→OptionRowLHN→ renders green dot in LHNThe Fix (PR #78421)
Added an early membership check at the top of
isPayer():This ensures that when the policy is removed from Onyx (user left workspace),
isPayer()immediately returnsfalse, preventing the entire downstream chain.Files Changed
src/libs/actions/Policy/Policy.ts— Added early return logicsrc/pages/workspace/WorkspaceOverviewPage.tsx— Minor related updatesrc/pages/workspace/WorkspacesListPage.tsx— Minor related updatetests/actions/PolicyTest.ts— Added test coverage for the fixmarufsharifi commentedon Mar 2, 2026
@garrettmknight, @mallenexpensify, please process the payment for this issue. thanks.
rojiphil commentedon Mar 2, 2026
BugZero Checklist:
[Contributor] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.
Link to comment
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: Not Required. The existing checklist is good enough to capture such issues.
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Link to issue: https://github.com/Expensify/Expensify/issues/606339
Regression Test Proposal
Precondition:
Owner create workspace, invites Employee, and makes the Employee as Approver. Submission frequency in Workflows needs to be disabled
Test:
Steps:
Do we agree 👍 or 👎
Zapier Logs
Run ID: 00040eee-f8d3-a914-b727-d2c40114a844mallenexpensify commentedon Mar 2, 2026
Payment Summary
Contributor: @marufsharifi paid $250 via Upwork
Contributor+: @rojiphil due $250 via NewDot
@marufsharifi can you please accept the job below? Please reply here and tag me once you have.
https://www.upwork.com/jobs/~022028588785847055154
^ Test case created. Thx Roji
marufsharifi commentedon Mar 3, 2026
@mallenexpensify, I've accepted. the offer. thanks.
mallenexpensify commentedon Mar 4, 2026
@marufsharifi paid, summary updated above. Thx
quinthar commentedon Apr 13, 2026
Approved $250 to @rojiphil